// ################################
// ##  Objekty lodi a zakladen   ##
// ##   a objekty jejich casti   ##
// ################################

#include "fortress_skelet.h"

#include <cassert>
//#include <typeinfo>
#include <cmath>
#include <algorithm>
#include <set>
#include <limits>

#ifdef _DEBUG
#include <sstream>
#include "log.h"
#endif

#include "error_handling.h"
#include "time_mapping.h"
#include "independent_constants.h"
#include "physics.h"

#include "context.h"
#include "space.h"
#include "spaceindex.h"
#include "time_axis.h"
#include "cache_data.h"
#include "players_realms.h"
#include "prot_srv.h"

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

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

bool tradeBundleClass::isEqual(const tradeBundleClass & secondBundle)
{
	if ((this->quarkGluonPlasma_ != secondBundle.quarkGluonPlasma_) ||
		(this->ulrea_            != secondBundle.ulrea_           ) ||
		(this->heavyWater_       != secondBundle.heavyWater_      ) ||
		(this->deuterium_        != secondBundle.deuterium_       ) ||
		(this->zirconiumCrystal_ != secondBundle.zirconiumCrystal_) ||
		(this->energy_           != secondBundle.energy_          ) ||
		(this->ilmenite_         != secondBundle.ilmenite_        ) ||
		(this->titanium_         != secondBundle.titanium_        ))
	{
		return 0;
	}

	tradeMap::const_iterator litp1 = this->itemsMap_.begin();
	tradeMap::const_iterator litp2 = secondBundle.itemsMap_.begin();

	while ((this->itemsMap_.end() != litp1) && (secondBundle.itemsMap_.end() != litp2))
	{
		if ((litp1->first               == litp2->first              ) &&
			(litp1->second.workingCount == litp2->second.workingCount) &&
			(litp1->second.damagedCount == litp2->second.damagedCount))
		{
			litp1++;
			litp2++;
		}
		else
		{
			return 0;
		}
	}

	if ((this->itemsMap_.end() != litp1) || (secondBundle.itemsMap_.end() != litp2))
	{
		return 0;
	}

	return 1;
};

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

bool tradeBundleClass::isItemInBundleInCorrectCount(commonItemClass * item)
{
	if (!item)
	{
		return 0;
	}

	tradeMap::iterator itemIterator = this->itemsMap_.find(item->getID());

	if (this->itemsMap_.end() == itemIterator)
	{
		return 0;
	}

	if (item->isStackable())
	{
		stackableItemClass * stackableItem = (stackableItemClass *)item;
		if (stackableItem->getWorking() < itemIterator->second.workingCount)
		{
			return 0;
		}
		if (stackableItem->getDamaged() < itemIterator->second.damagedCount)
		{
			return 0;
		}
	}
	else
	{
		if ((1 != itemIterator->second.workingCount) || (0 != itemIterator->second.damagedCount))
		{
			return 0;
		}
	}

	return 1;
};

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

unsigned long long tradeBundleClass::containeredResourcesSize()
{
	return ullUpRound
		   (
		   (double)this->heavyWater_       / (double)HEAVY_WATER_DENSITY       +
		   (double)this->deuterium_        / (double)DEUTERIUM_DENSITY         +
		   (double)this->zirconiumCrystal_ / (double)ZIRCONIUM_CRYSTAL_DENSITY +
		   (double)this->ilmenite_         / (double)ILMENITE_DENSITY          +
		   (double)this->titanium_         / (double)TITANIUM_DENSITY          
		   );
};

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

bool tradeBundleClass::checkStorageOwnershipAndValidity(fortressClass * owner)
{
	if ((owner->quarkGluonPlasmaInMg(0) < this->quarkGluonPlasma_) ||
		(owner->ulreiCount(0)           < this->ulrea_           ) ||
		(owner->heavyWaterInKg(0)       < this->heavyWater_      ) ||
		(owner->deuteriumInKg(0)        < this->deuterium_       ) ||
		(owner->zirconiumCrystalInKg(0) < this->zirconiumCrystal_) ||
		(owner->energyInTJ(0)           < this->energy_          ) ||
		(owner->ilmeniteInKg(0)         < this->ilmenite_        ) ||
		(owner->titaniumInKg(0)         < this->titanium_        ))
	{
		return 0;
	}
       
	unsigned long matchesRequested = (unsigned long)this->itemsMap_.size();
	unsigned long matches          = 0;

	if (this->isItemInBundleInCorrectCount(owner->warehouse.magneticalGrid()))
	{
		matches++;
	}

	if (this->isItemInBundleInCorrectCount(owner->warehouse.transportContainer()))
	{
		matches++;
	}

	if (this->isItemInBundleInCorrectCount(owner->warehouse.energeticCell()))
	{
		matches++;
	}

	if (matchesRequested == matches)
	{
		return 1;
	}

	for (dtIdentifierList::iterator litp1 = owner->warehouse.storageBegin(); owner->warehouse.storageEnd() != litp1; litp1++)
	{
		if (this->isItemInBundleInCorrectCount(*litp1))
		{
			matches++;
		}
		if (matchesRequested == matches)
		{
			return 1;
		}
	}

	return 0;
};

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

void tradeBundleClass::clearBundleToMatchAShell(fortressClass * shell)
{
	if (!(shell->isShell(0)))
	{
		errLogicalError("Clearing shell (ID %u) which is not a shell.", (unsigned long long)shell->getID());
		return;
	}

	this->updateWeightAndSize(0);

	baseClass * baseShell = (baseClass *)shell;

	this->quarkGluonPlasma_ = 0;
	this->ulrea_            = 0;
	this->heavyWater_       = 0;
	this->deuterium_        = 0;
	this->zirconiumCrystal_ = 0;
	this->energy_           = this->energy_;
	this->ilmenite_         = 0;
	this->titanium_         = this->titanium_;

	dtIdentifier       androidsID            = NOT_VALID_ID;
	dtIdentifier       energeticCellsID      = NOT_VALID_ID;
	unsigned long long workingAndroids       = 0;
	unsigned long long workingEnergeticCells = 0;

	for (tradeMap::iterator litp1 = this->itemsMap_.begin(); this->itemsMap_.end() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(litp1->first);
		if (PATTERN_ID_ANDROIDS == item->getPatternID())
		{
			androidsID       = litp1->first;
			workingAndroids += litp1->second.workingCount;
		}
		if (PATTERN_ID_ENERGETIC_CELL == item->getPatternID())
		{
			energeticCellsID       = litp1->first;
			workingEnergeticCells += litp1->second.workingCount;
		}
	}

	this->itemsMap_.clear();
	this->quarkGluonPlasmaFreeSpace_     = 0;
	this->containeredResourcesFreeSpace_ = 0;
	this->energyFreeSpace_               = 0;
	this->itemsWeight_                   = 0;
	this->itemsSize_                     = 0;

	if ((NOT_VALID_ID != androidsID) && (0 < workingAndroids))
	{
		workingAndroids = min(workingAndroids, baseShell->maxAndroidsShellCanAccept((androidsClass *)(this->getItemByID(androidsID))));
		this->insertItem(androidsID, workingAndroids, 0);
	}
	if ((NOT_VALID_ID != energeticCellsID) && (0 < workingEnergeticCells))
	{
		workingEnergeticCells = min(workingEnergeticCells, baseShell->maxEnergeticCellsShellCanAccept((energeticCellClass *)(this->getItemByID(energeticCellsID))));
		this->insertItem(energeticCellsID, workingEnergeticCells, 0);
	}
	this->energy_   = min(this->energy_  , baseShell->maxEnergyShellCanAccept()  );
	this->titanium_ = min(this->titanium_, baseShell->maxTitaniumShellCanAccept());
};

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

void tradeBundleClass::updateWeightAndSize(bool validateItemsCounts)
{
	this->quarkGluonPlasmaFreeSpace_      = 0;
	this->containeredResourcesFreeSpace_  = 0;
	this->energyFreeSpace_                = 0;

	this->itemsWeight_                    = 0;
	this->itemsSize_                      = 0;

	this->itemsWeight_                   += this->heavyWater_;
	this->itemsWeight_                   += this->deuterium_;
	this->itemsWeight_                   += this->zirconiumCrystal_;
	this->itemsWeight_                   += this->ilmenite_;
	this->itemsWeight_                   += this->titanium_;

	for (tradeMap::iterator litp1 = this->itemsMap_.begin(); this->itemsMap_.end() != litp1; litp1++)
	{
		commonItemClass * actualItem = actx->cacheItemsList.getItem<commonItemClass>(litp1->first);
		if (validateItemsCounts)
		{
			if (actualItem->isStackable())
			{
				stackableItemClass * actualStackableItem = (stackableItemClass *)actualItem;
				litp1->second.workingCount = min(litp1->second.workingCount, actualStackableItem->getWorking());
				litp1->second.damagedCount = min(litp1->second.damagedCount, actualStackableItem->getDamaged());
			}
			else
			{
				litp1->second.workingCount = 1;
				litp1->second.damagedCount = 0;
			}
		}
		if (actualItem->isStackable())
		{
			stackableItemClass * actualStackableItem = (stackableItemClass *)actualItem;
			if (PATTERN_ID_MAGNETICAL_GRID     == actualStackableItem->getPatternID())
			{
				this->quarkGluonPlasmaFreeSpace_     += (unsigned long long)(litp1->second.workingCount) * (unsigned long long)((magneticalGridClass     *)(actualStackableItem))->actualCapacity();
			}
			if (PATTERN_ID_TRANSPORT_CONTAINER == actualStackableItem->getPatternID())
			{
				this->containeredResourcesFreeSpace_ += (unsigned long long)(litp1->second.workingCount) * (unsigned long long)((transportContainerClass *)(actualStackableItem))->actualCapacity();
			}
			if (PATTERN_ID_ENERGETIC_CELL      == actualStackableItem->getPatternID())
			{
				this->energyFreeSpace_               += (unsigned long long)(litp1->second.workingCount) * (unsigned long long)((energeticCellClass      *)(actualStackableItem))->actualCapacity();
			}
		}
		unsigned long long count  = litp1->second.workingCount + litp1->second.damagedCount;
		this->itemsWeight_  += (unsigned long long)count * (unsigned long long)actualItem->getWeight();
		this->itemsSize_    += (unsigned long long)count * (unsigned long long)actualItem->getSize();
	}
};

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

void tradeBundleClass::insertItem(commonItemClass * newItem, unsigned long long working, unsigned long long damaged)
{
	dtIdentifier            itemID  = newItem->getID();

	if (newItem->isStackable())
	{
		stackableItemClass * newStackableItem = (stackableItemClass *)(newItem);
		working = min(working, newStackableItem->getWorking());
		damaged = min(damaged, newStackableItem->getDamaged());
		if (PATTERN_ID_MAGNETICAL_GRID     == newStackableItem->getPatternID())
		{
			this->quarkGluonPlasmaFreeSpace_     += (unsigned long long)working * (unsigned long long)((magneticalGridClass     *)(newStackableItem))->actualCapacity();
		}
		if (PATTERN_ID_TRANSPORT_CONTAINER == newStackableItem->getPatternID())
		{
			this->containeredResourcesFreeSpace_ += (unsigned long long)working * (unsigned long long)((transportContainerClass *)(newStackableItem))->actualCapacity();
		}
		if (PATTERN_ID_ENERGETIC_CELL      == newStackableItem->getPatternID())
		{
			this->energyFreeSpace_               += (unsigned long long)working * (unsigned long long)((energeticCellClass      *)(newStackableItem))->actualCapacity();
		}
	}
	else
	{
		working = min(1, working);
		damaged =     0          ;
	}

	if (!(0 < working + damaged))
	{
		return;
	}

	tradableItemCountsClass counts    (working, damaged);
	unsigned long long      count   = working + damaged;
	unsigned long long      weight  = (unsigned long long)count * (unsigned long long)newItem->getWeight();
	unsigned long long      size    = (unsigned long long)count * (unsigned long long)newItem->getSize();

	this->itemsWeight_             += weight;
	this->itemsSize_               += size;

	tradeMap::iterator newItemIterator = this->itemsMap_.find(itemID);
	if (this->itemsMap_.end() == newItemIterator)
	{
		this->itemsMap_.insert(make_pair(itemID, counts));
	}
	else
	{
		newItemIterator->second.workingCount += counts.workingCount;
		newItemIterator->second.damagedCount += counts.damagedCount;
	}
};

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

void tradeBundleClass::deleteItem(tradeMap::iterator oldIterator, unsigned long long working, unsigned long long damaged)
{
	commonItemClass * oldItem         = actx->cacheItemsList.getItem<commonItemClass>(oldIterator->first);

	working                           = min(working, oldIterator->second.workingCount);
	damaged                           = min(damaged, oldIterator->second.damagedCount);

	if (oldItem->isStackable())
	{
		stackableItemClass * oldStackableItem = (stackableItemClass *)oldItem;
		if (PATTERN_ID_MAGNETICAL_GRID     == oldStackableItem->getPatternID())
		{
			this->quarkGluonPlasmaFreeSpace_     -= min(this->quarkGluonPlasmaFreeSpace_    , (unsigned long long)working * (unsigned long long)((magneticalGridClass     *)(oldStackableItem))->actualCapacity());
		}
		if (PATTERN_ID_TRANSPORT_CONTAINER == oldStackableItem->getPatternID())
		{
			this->containeredResourcesFreeSpace_ -= min(this->containeredResourcesFreeSpace_, (unsigned long long)working * (unsigned long long)((transportContainerClass *)(oldStackableItem))->actualCapacity());
		}
		if (PATTERN_ID_ENERGETIC_CELL      == oldStackableItem->getPatternID())
		{
			this->energyFreeSpace_               -= min(this->energyFreeSpace_              , (unsigned long long)working * (unsigned long long)((energeticCellClass      *)(oldStackableItem))->actualCapacity());
		}
	}

	unsigned long long count          = working + damaged;
	unsigned long long weight         = (unsigned long long)count * (unsigned long long)oldItem->getWeight();
	unsigned long long size           = (unsigned long long)count * (unsigned long long)oldItem->getSize();

	this->itemsWeight_               -= min(this->itemsWeight_, weight);
	this->itemsSize_                 -= min(this->itemsSize_  , size  );

	oldIterator->second.workingCount -= min(oldIterator->second.workingCount, working);
	oldIterator->second.damagedCount -= min(oldIterator->second.damagedCount, damaged);

	if (!(0 < oldIterator->second.workingCount + oldIterator->second.damagedCount))
	{
		this->itemsMap_.erase(oldIterator);
	}
};

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

bool tradeBundleClass::deleteItem(commonItemClass * oldItem, unsigned long long working, unsigned long long damaged)
{
	dtIdentifier oldItemID = oldItem->getID();

	for (tradeMap::iterator litp1 = this->itemsMap_.begin(); this->itemsMap_.end() != litp1; litp1++)
	{
		if (litp1->first == oldItemID)
		{
			this->deleteItem(litp1, working, damaged);
			return 1;
		}
	}

	return 0;
};

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

bool tradeBundleClass::getItemsRecord(dtIdentifier itemID, unsigned long long & working, unsigned long long & damaged)
{
	tradeMap::iterator itemIterator = this->itemsMap_.find(itemID);
	if (this->itemsMap_.end() == itemIterator)
	{
		working = 0;
		damaged = 0;
		return 0;
	}
	else
	{
		working = itemIterator->second.workingCount;
		damaged = itemIterator->second.damagedCount;
		return 1;
	}
};

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

unsigned long long structuralIntegrityVoidSectionClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (owningFortress_->actualStructuralIntegrity() < owningFortress_->totalStructuralIntegrity())
	{
		result += this->getMaxRepairingMechanicsBySize(owningFortress_->getSize());
	}
	return result;
};

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

void structuralIntegrityVoidSectionClass::androidsDistribution(unsigned long long &hullPts, unsigned long androidsPower)
{	
	unsigned long long hullReq       = 0;
	if (owningFortress_->actualStructuralIntegrity() < owningFortress_->totalStructuralIntegrity())
	{
		hullReq += this->getMaxRepairingMechanicsBySize(owningFortress_->getSize());
	}
	unsigned long long hullGot       = min(hullReq, this->androidsAssignment.assignedDroids);
	                   hullPts       = (unsigned long long)hullGot * (unsigned long long)androidsPower;
};

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

void structuralIntegrityVoidSectionClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower   = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsigned long long hullPts         = 0;
	this->androidsDistribution(hullPts, androidsPower);
	this->structuralIntegrityGradient_ = (double)hullPts * (double)owningFortress_->totalStructuralIntegrity() / (double)owningFortress_->getWeight();
	owningFortress->repairStructualIntegrity((unsigned long long)(this->structuralIntegrityGradient_ * (double)seconds));
};

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

unsigned long long structuralIntegrityVoidSectionClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsigned long long hullPts       = 0;
	this->androidsDistribution(hullPts, androidsPower);
	if (0 < ((double)hullPts * (double)owningFortress_->totalStructuralIntegrity() / (double)owningFortress_->getWeight()))
	{
		return min(maxSecondsToChange, ullUpRound((double)(owningFortress_->missingStructuralIntegrity()) / ((double)hullPts * (double)owningFortress_->totalStructuralIntegrity() / (double)owningFortress_->getWeight())));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

energeticAccumulatorClass * energeticSystemClass::energeticAccumulator()
{
	if (energeticAccumulatorClass * result = actx->cacheItemsList.getItem<energeticAccumulatorClass>(energeticAccumulatorID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullEnergeticAccumulatorClass>(PATTERN_ID_ENERGETIC_ACCUMULATOR);
	}
};

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

dtIdentifier energeticSystemClass::changeEnergeticAccumulator(dtIdentifier newID)
{
	dtIdentifier oldAccumulator   = this->energeticAccumulatorID_;
	this->energeticAccumulatorID_ = newID;

	this->energeticAccumulatorEnergyState.energy       = 0;
	this->energeticAccumulatorEnergyState.targetEnergy = this->energeticAccumulator()->clientAccumulator();

	return oldAccumulator;
}

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

void energeticSystemClass::annihilate()
{
	if (this->avalEnergeticAccumulator())
	{
		actx->cacheItemsList.deleteItem(this->energeticAccumulatorID_);
		this->energeticAccumulatorID_ = NOT_VALID_ID;
	}
}

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

unsigned long long energeticSystemClass::getEnergeticSystemWeight()
{
	return (unsigned long long)energeticAccumulator()->getWeight();
};

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

unsigned long long energeticSystemClass::getEnergy(fortressClass * owner)
{
	return this->energeticAccumulatorEnergyState.energy + (unsigned long long)owner->getEnergyGrowthByGradient(this->getGradient(owner));
};

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

double energeticSystemClass::getGradient(fortressClass * owningFortress)
{
	if (!(this->isGradientCalculated_))
	{
		owningFortress->energyDistributionPhaseAndWeaponsFire();
		this->isGradientCalculated_ = 1;
	}
	return this->gradient_;
};

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

unsigned long long energeticSystemClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->energeticAccumulator()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->energeticAccumulator()->getSize());
	}
	return result;
};

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

void energeticSystemClass::androidsDistribution(unsigned long long &accPts, unsigned long androidsPower)
{
	unsigned long long accReq        = 0;
	if (0 < this->energeticAccumulator()->getDamage())
	{
		accReq += this->getMaxRepairingMechanicsBySize(this->energeticAccumulator()->getSize());
	}
	unsigned long long accGot        = min(accReq, this->androidsAssignment.assignedDroids);
	                   accPts        = (unsigned long long)accGot * (unsigned long long)androidsPower;
};

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

void energeticSystemClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long accPts        = 0;
	this->androidsDistribution(accPts, androidsPower);
	this->energeticAccumulator()->repair(accPts * seconds);
};

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

unsigned long long energeticSystemClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long accPts        = 0;
	this->androidsDistribution(accPts, androidsPower);
	if (0 < accPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->energeticAccumulator()->pointsToCheckpoint(), accPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

navigationComputerClass * subspaceDriveClass::navigationComputer()
{ 
	if (navigationComputerClass * result = actx->cacheItemsList.getItem<navigationComputerClass>(navigationComputerID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullNavigationComputerClass>(PATTERN_ID_NAVIGATION_COMPUTER);
	}
};

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

quarkGluonCoreClass * subspaceDriveClass::quarkGluonCore()
{ 
	if (quarkGluonCoreClass * result = actx->cacheItemsList.getItem<quarkGluonCoreClass>(quarkGluonCoreID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullQuarkGluonCoreClass>(PATTERN_ID_QUARK_GLUON_CORE);
	}
};

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

subspaceBeaconClass * subspaceDriveClass::subspaceBeacon()
{
	if (subspaceBeaconClass * result = actx->cacheItemsList.getItem<subspaceBeaconClass>(subspaceBeaconID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullSubspaceBeaconClass>(PATTERN_ID_SUBSPACE_BEACON);
	}
};

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

inertialDampersClass * subspaceDriveClass::inertialDampers()
{
	if (inertialDampersClass * result = actx->cacheItemsList.getItem<inertialDampersClass>(inertialDampersID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullInertialDampersClass>(PATTERN_ID_INERTIAL_DAMPERS);
	}
};

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

void subspaceDriveClass::annihilate()
{
	if (this->avalQuarkGluonCore())
	{
		actx->cacheItemsList.deleteItem(this->quarkGluonCoreID_);
		this->quarkGluonCoreID_ = NOT_VALID_ID;
	}
	if (this->avalNavigationComputer())
	{
		actx->cacheItemsList.deleteItem(this->navigationComputerID_);
		this->navigationComputerID_ = NOT_VALID_ID;
	}
	if (this->avalSubspaceBeacon())
	{
		actx->cacheItemsList.deleteItem(this->subspaceBeaconID_);
		this->subspaceBeaconID_ = NOT_VALID_ID;
	}
	if (this->avalInertialDampers())
	{
		actx->cacheItemsList.deleteItem(this->inertialDampersID_);
		this->inertialDampersID_ = NOT_VALID_ID;
	}
};

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

unsigned long long subspaceDriveClass::getSubspaceDriveWeight()
{
	return (unsigned long long)quarkGluonCore()->getWeight()     +
		   (unsigned long long)navigationComputer()->getWeight() +
		   (unsigned long long)subspaceBeacon()->getWeight()     +
		   (unsigned long long)inertialDampers()->getWeight();
};

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

unsigned long long subspaceDriveClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->navigationComputer()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->navigationComputer()->getSize());
	}
	if (0 < this->quarkGluonCore()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->quarkGluonCore()->getSize());
	}
	if (0 < this->subspaceBeacon()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->subspaceBeacon()->getSize());
	}
	if (0 < this->inertialDampers()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->inertialDampers()->getSize());
	}
	return result;
};

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

void subspaceDriveClass::androidsDistribution(unsigned long long &jetPts, unsigned long long &cmpPts, unsigned long long &becPts, unsigned long long &damPts, unsigned long androidsPower)
{
	unsigned long long jetReq        = 0;
	unsigned long long cmpReq        = 0;
	unsigned long long becReq        = 0;
	unsigned long long damReq        = 0;
	if (0 < this->quarkGluonCore()->getDamage())
	{
		jetReq += this->getMaxRepairingMechanicsBySize(this->quarkGluonCore()->getSize());
	}
	if (0 < this->navigationComputer()->getDamage())
	{
		cmpReq += this->getMaxRepairingMechanicsBySize(this->navigationComputer()->getSize());
	}
	if (0 < this->subspaceBeacon()->getDamage())
	{
		becReq += this->getMaxRepairingMechanicsBySize(this->subspaceBeacon()->getSize());
	}
	if (0 < this->inertialDampers()->getDamage())
	{
		damReq += this->getMaxRepairingMechanicsBySize(this->inertialDampers()->getSize());
	}
	unsigned long long jetGot        = 0;
	unsigned long long cmpGot        = 0;
	unsigned long long becGot        = 0;
	unsigned long long damGot        = 0;
	if (this->androidsAssignment.assignedDroids < jetReq + cmpReq + becReq + damReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&jetGot, jetReq));
		piles.push_back(make_pair(&cmpGot, cmpReq));
		piles.push_back(make_pair(&becGot, becReq));
		piles.push_back(make_pair(&damGot, damReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		jetGot                       = jetReq;
		cmpGot                       = cmpReq;
		becGot                       = becReq;
		damGot                       = damReq;
	}
	                   jetPts        = (unsigned long long)jetGot * (unsigned long long)androidsPower;
					   cmpPts        = (unsigned long long)cmpGot * (unsigned long long)androidsPower;
					   becPts        = (unsigned long long)becGot * (unsigned long long)androidsPower;
					   damPts        = (unsigned long long)damGot * (unsigned long long)androidsPower;
};

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

void subspaceDriveClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long jetPts        = 0;
	unsigned long long cmpPts        = 0;
	unsigned long long becPts        = 0;
	unsigned long long damPts        = 0;
	this->androidsDistribution(jetPts, cmpPts, becPts, damPts, androidsPower);
	this->quarkGluonCore()->repair    (jetPts * seconds);
	this->navigationComputer()->repair(cmpPts * seconds);
	this->subspaceBeacon()->repair    (becPts * seconds);
	this->inertialDampers()->repair   (damPts * seconds);
};

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

unsigned long long subspaceDriveClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long jetPts        = 0;
	unsigned long long cmpPts        = 0;
	unsigned long long becPts        = 0;
	unsigned long long damPts        = 0;
	this->androidsDistribution(jetPts, cmpPts, becPts, damPts, androidsPower);
	unsigned long long secondsToJet  = maxSecondsToChange;
	unsigned long long secondsToCmp  = maxSecondsToChange;
	unsigned long long secondsToBec  = maxSecondsToChange;
	unsigned long long secondsToDam  = maxSecondsToChange;
	if (0 < jetPts)
	{
		secondsToJet = ullUpRoundDiv(this->quarkGluonCore()->pointsToCheckpoint(), jetPts);
	}
	if (0 < cmpPts)
	{
		secondsToCmp = ullUpRoundDiv(this->navigationComputer()->pointsToCheckpoint(), cmpPts);
	}
	if (0 < becPts)
	{
		secondsToBec = ullUpRoundDiv(this->subspaceBeacon()->pointsToCheckpoint(), becPts);
	}
	if (0 < damPts)
	{
		secondsToDam = ullUpRoundDiv(this->inertialDampers()->pointsToCheckpoint(), damPts);
	}
	return min(maxSecondsToChange, 
		   min(secondsToJet, 
		   min(secondsToCmp, 
		   min(secondsToBec,
		       secondsToDam))));
};

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

impulsJetEngineClass * impulsDriveClass::impulsJetEngine()
{
	if (impulsJetEngineClass * result = actx->cacheItemsList.getItem<impulsJetEngineClass>(impulsJetEngineID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullImpulsJetEngineClass>(PATTERN_ID_IMPULS_JET_ENGINE);
	}
};

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

mechanicalDampersClass * impulsDriveClass::mechanicalDampers()
{
	if (mechanicalDampersClass * result = actx->cacheItemsList.getItem<mechanicalDampersClass>(mechanicalDampersID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullMechanicalDampersClass>(PATTERN_ID_MECHANICAL_DAMPERS);
	}
};

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

void impulsDriveClass::annihilate()
{
	if (this->avalImpulsJetEngine())
	{
		actx->cacheItemsList.deleteItem(this->impulsJetEngineID_);
		this->impulsJetEngineID_ = NOT_VALID_ID;
	}
	if (this->avalMechanicalDampers())
	{
		actx->cacheItemsList.deleteItem(this->mechanicalDampersID_);
		this->mechanicalDampersID_ = NOT_VALID_ID;
	}
};

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

unsigned long long impulsDriveClass::getImpulsDriveWeight()
{
	return (unsigned long long)impulsJetEngine()->getWeight()   +
		   (unsigned long long)mechanicalDampers()->getWeight();
};

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

unsigned long long impulsDriveClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->impulsJetEngine()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->impulsJetEngine()->getSize());
	}
	if (0 < this->mechanicalDampers()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->mechanicalDampers()->getSize());
	}
	return result;
};

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

void impulsDriveClass::androidsDistribution(unsigned long long &jetPts, unsigned long long &damPts, unsigned long androidsPower)
{
	unsigned long long jetReq        = 0;
	unsigned long long damReq        = 0;
	if (0 < this->impulsJetEngine()->getDamage())
	{
		jetReq += this->getMaxRepairingMechanicsBySize(this->impulsJetEngine()->getSize());
	}
	if (0 < this->mechanicalDampers()->getDamage())
	{
		damReq += this->getMaxRepairingMechanicsBySize(this->mechanicalDampers()->getSize());
	}
	unsigned long long jetGot        = 0;
	unsigned long long damGot        = 0;
	if (this->androidsAssignment.assignedDroids < jetReq + damReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&jetGot, jetReq));
		piles.push_back(make_pair(&damGot, damReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		jetGot                       = jetReq;
		damGot                       = damReq;
	}
	                   jetPts        = (unsigned long long)jetGot * (unsigned long long)androidsPower;
					   damPts        = (unsigned long long)damGot * (unsigned long long)androidsPower;
};

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

void impulsDriveClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long jetPts        = 0;
	unsigned long long damPts        = 0;
	this->androidsDistribution(jetPts, damPts, androidsPower);
	this->impulsJetEngine()->repair  (jetPts * seconds);
	this->mechanicalDampers()->repair(damPts * seconds);
};

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

unsigned long long impulsDriveClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long jetPts        = 0;
	unsigned long long damPts        = 0;
	this->androidsDistribution(jetPts, damPts, androidsPower);
	unsigned long long secondsToJet  = maxSecondsToChange;
	unsigned long long secondsToDam  = maxSecondsToChange;
	if (0 < jetPts)
	{
		secondsToJet = ullUpRoundDiv(this->impulsJetEngine()->pointsToCheckpoint(), jetPts);
	}
	if (0 < damPts)
	{
		secondsToDam = ullUpRoundDiv(this->mechanicalDampers()->pointsToCheckpoint(), damPts);
	}
	return min(maxSecondsToChange, min(secondsToJet, secondsToDam));
};

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

deflectorShieldsGeneratorClass * deflectorShieldsClass::deflectorShieldsGenerator()
{
	if (deflectorShieldsGeneratorClass * result = actx->cacheItemsList.getItem<deflectorShieldsGeneratorClass>(deflectorShieldsGeneratorID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullDeflectorShieldsGeneratorClass>(PATTERN_ID_DEFLECTOR_SHIELDS);
	}
};

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

unsigned long long deflectorShieldsClass::getEnergy(fortressClass * owner)
{
	return this->deflectorShieldsEnergyState.energy + (unsigned long long)owner->getEnergyGrowthByGradient(this->getGradient());
};

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

void deflectorShieldsClass::annihilate()
{
	if (this->avalDeflectorShieldsGenerator())
	{
		actx->cacheItemsList.deleteItem(this->deflectorShieldsGeneratorID_);
		this->deflectorShieldsGeneratorID_ = NOT_VALID_ID;
	}
};

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

unsigned long long deflectorShieldsClass::getDeflectorShieldsWeight()
{
	return (unsigned long long)(deflectorShieldsGenerator()->getWeight());
};

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

unsigned long long deflectorShieldsClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->deflectorShieldsGenerator()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->deflectorShieldsGenerator()->getSize());
	}
	return result;
};

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

void deflectorShieldsClass::androidsDistribution(unsigned long long &defPts, unsigned long androidsPower)
{
	unsigned long long defReq        = 0;
	if (0 < this->deflectorShieldsGenerator()->getDamage())
	{
		defReq += this->getMaxRepairingMechanicsBySize(this->deflectorShieldsGenerator()->getSize());
	}
	unsigned long long defGot        = min(defReq, this->androidsAssignment.assignedDroids);
	                   defPts        = (unsigned long long)defGot * (unsigned long long)androidsPower;
};

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

void deflectorShieldsClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsigned long long defPts        = 0;
	this->androidsDistribution(defPts, androidsPower);
	this->deflectorShieldsGenerator()->repair(defPts * seconds);
};

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

unsigned long long deflectorShieldsClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsigned long long defPts        = 0;
	this->androidsDistribution(defPts, androidsPower);
	if (0 < defPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->deflectorShieldsGenerator()->pointsToCheckpoint(), defPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

bool weaponsClass::mountDroneMissileLauncher(fortressClass * owningFortress, dtIdentifier newID)
{
	if ((!owningFortress                                                                                                             ) ||
		(owningFortress->getFortressClass()->getMaxDroneMissileLaunchers() <= droneMissileLaunchersIDs_.size()                       ) ||
		(owningFortress->getFortressClass()->getMaxWeapons()               <= droneMissileLaunchersIDs_.size() + laserGunsIDs_.size()))
	{
		return 0;
	}
	if (NOT_VALID_ID == newID)
	{
		return 1;
	}
	droneMissileLauncherClass * dml = actx->cacheItemsList.getItem<droneMissileLauncherClass>(newID);
	if (!dml)
	{
		errExceptionError("Invalid item reference (ID %u).", (unsigned long long)newID);
		return 0;
	}
	energyStateClass es;
	es.energy       = 0;
	es.targetEnergy = dml->clientAccumulator();
	droneMissileLaunchersIDs_.push_back(make_pair(newID, es));
	return 1;
};

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

bool weaponsClass::mountLaserGun(fortressClass * owningFortress, dtIdentifier newID)
{
	if ((!owningFortress                                                                                                 ) ||
		(owningFortress->getFortressClass()->getMaxLaserGuns() <= laserGunsIDs_.size()                                   ) ||
		(owningFortress->getFortressClass()->getMaxWeapons()   <= laserGunsIDs_.size() + droneMissileLaunchersIDs_.size()) ||
		(NOT_VALID_ID == newID))
	{
		return 0;
	}
	if (NOT_VALID_ID == newID)
	{
		return 1;
	}
	laserGunClass * lg = actx->cacheItemsList.getItem<laserGunClass>(newID);
	if (!lg)
	{
		errExceptionError("Invalid item reference (ID %u).", (unsigned long long)newID);
		return 0;
	}
	energyStateClass es;
	es.energy       = 0;
	es.targetEnergy = lg->clientAccumulator();
	laserGunsIDs_.push_back(make_pair(newID, es));
	return 1;
};

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

weaponEnergyCircuitClass * weaponsClass::weaponEnergyCircuit()
{
	if (weaponEnergyCircuitClass * result = actx->cacheItemsList.getItem<weaponEnergyCircuitClass>(weaponEnergyCircuitID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullWeaponEnergyCircuitClass>(PATTERN_ID_WEAPON_ENERGY_CIRCUIT);
	}
};

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

droneMissilesClass * weaponsClass::droneMissiles()
{ 
	if (droneMissilesClass * result = actx->cacheItemsList.getItem<droneMissilesClass>(droneMissilesID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullDroneMissilesClass>(PATTERN_ID_DRONE_MISSILES);
	}
};

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

unsigned long long weaponsClass::getTotalWeaponsCharging(fortressClass * owner, unsigned long long * resultWithoutCircuit)
{
	unsigned long long droneMissileLaunchersCharging = 0;
	unsigned long long laserGunsCharging             = 0;
	
	droneMissileLauncherPEnergyStatePPair dml;
	for (unsigned long loop1 = 0; NULL != (dml = droneMissileLaunchers(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owner, dml.first, dml.second))
		{
			droneMissileLaunchersCharging += dml.first->actualCharging();
		}
	}

	laserGunPEnergyStatePPair lg;
	for (unsigned long loop1 = 0; NULL != (lg = laserGuns(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owner, lg.first, lg.second))
		{
			laserGunsCharging += lg.first->actualCharging();
		}
	}

	if (resultWithoutCircuit)
	{
		(*resultWithoutCircuit) = droneMissileLaunchersCharging + laserGunsCharging;
	}

	return min(droneMissileLaunchersCharging + laserGunsCharging, (unsigned long long)weaponEnergyCircuit()->actualCharging());
};

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

void weaponsClass::annihilate()
{
	if (this->avalWeaponEnergyCircuit())
	{
		actx->cacheItemsList.deleteItem(this->weaponEnergyCircuitID_);
		this->weaponEnergyCircuitID_ = NOT_VALID_ID;
	}
	if (this->avalDroneMissiles())
	{
		actx->cacheItemsList.deleteItem(this->droneMissilesID_);
		this->droneMissilesID_ = NOT_VALID_ID;
	}
	if (this->avalDroneMissileLaunchers())
	{
		for (dtIdentifierEnergyStatePairDeque::iterator litp1 = this->droneMissileLaunchersIDs_.begin(); this->droneMissileLaunchersIDs_.end() != litp1; litp1++)
		{
			actx->cacheItemsList.deleteItem(litp1->first);
		}
		this->droneMissileLaunchersIDs_.clear();
	}
	if (this->avalLaserGuns())
	{
		for (dtIdentifierEnergyStatePairDeque::iterator litp1 = this->laserGunsIDs_.begin(); this->laserGunsIDs_.end() != litp1; litp1++)
		{
			actx->cacheItemsList.deleteItem(litp1->first);
		}
		this->laserGunsIDs_.clear();
	}
};

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

void weaponsClass::dischargeAllWeapons()
{
	for (dtIdentifierEnergyStatePairDeque::iterator litp1 = droneMissileLaunchersIDs_.begin(); droneMissileLaunchersIDs_.end() != litp1; litp1++)
	{
		litp1->second.energy = 0;
	}
	for (dtIdentifierEnergyStatePairDeque::iterator litp1 = laserGunsIDs_.begin()            ; laserGunsIDs_.end() != litp1            ; litp1++)
	{
		litp1->second.energy = 0;
	}
};

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

bool weaponsClass::isWeaponCharging(fortressClass * owner, commonItemClass * weapon, energyStateClass * es)
{
	droneMissileLauncherClass * dml = dynamic_cast<droneMissileLauncherClass *>(weapon);
	laserGunClass             * lg  = dynamic_cast<laserGunClass             *>(weapon);
	if (((owner                                                                                                ) &&
		 (dml                                                                                                  ) &&
		 (owner->getWeaponsTarget()                                                                            ) &&
		 (owner->weapons.droneMissiles()->actualLaunch(owner->getFortressRealmID()) <= dml->actualAccumulator()) &&
		 (0 < es->targetEnergy                                                                                 ) &&
		 (0 < owner->weapons.droneMissiles()->getWorking()                                                     ) &&
		 (0 < dml->actualCharging()                                                                            ))
		||
		((owner                                                                                                ) &&
		 (lg                                                                                                   ) &&
		 (owner->getWeaponsTarget()                                                                            ) &&
		 (0 < es->targetEnergy                                                                                 ) &&
		 (0 < lg->actualCharging()                                                                             )))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

unsigned long long weaponsClass::weaponFireLimit(fortressClass * owner, commonItemClass * weapon, energyStateClass * es)
{
	droneMissileLauncherClass * dml = dynamic_cast<droneMissileLauncherClass *>(weapon);
	laserGunClass             * lg  = dynamic_cast<laserGunClass             *>(weapon);
	unsigned long long accumulator = 0;
	unsigned long long charging    = 0;
	unsigned long long target      = 0;
	if (dml)
	{
		accumulator = dml->actualAccumulator();
		charging    = dml->clientCharging();
		target      = owner->weapons.droneMissiles()->actualLaunch(owner->getFortressRealmID());
	}
	if (lg)
	{
		accumulator = lg->actualAccumulator();
		charging    = lg->clientCharging();
		target      = es->targetEnergy;
	}
	return max(min(accumulator, target), charging * MIN_SECONDS_BETWEEN_WEAPONS_WHOLE_CHARGING); // je to provedeno tak, aby se to neupdatovalo casteji nez jednou za sekundu
};

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

unsigned long long weaponsClass::energyToWeaponFireLimit(fortressClass * owner, commonItemClass * weapon, energyStateClass * es)
{
	return ullSafeSub(this->weaponFireLimit(owner, weapon, es), es->energy);
};

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

bool weaponsClass::getDistanceToTheWeaponsTarget(fortressClass * owningFortress, dist_t & distance)
{
	if (!owningFortress)
	{
		distance = 0;
		return 0;
	}
	return owningFortress->getDistanceToTheWeaponsTarget(distance);
};

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

unsigned long long weaponsClass::getWeaponsWeight()
{
	unsigned long long droneMissileLaunchersWeight = 0;
	unsigned long long laserGunsWeight             = 0;
	
	droneMissileLauncherClass * dml;
	for (unsigned long loop1 = 0; NULL != (dml = droneMissileLaunchersOnly(loop1)); loop1++)
	{
		droneMissileLaunchersWeight += dml->getWeight();
	} 

	laserGunClass * lg;
	for (unsigned long loop1 = 0; NULL != (lg = laserGunsOnly(loop1)); loop1++)
	{
		laserGunsWeight += lg->getWeight();
	}

	return (unsigned long long)weaponEnergyCircuit()->getWeight()               +	
		   (unsigned long long)droneMissiles()->getAllStackedItemsTotalWeight() +
		   (unsigned long long)droneMissileLaunchersWeight                      +
		   (unsigned long long)laserGunsWeight;
};

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

unsigned long long weaponsClass::getDroneMissilesSize()
{
	return (unsigned long long)droneMissiles()->getAllStackedItemsTotalSize();
};

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

void weaponsClass::getEnergies(fortressClass * owningFortress, weaponIDGradientMap * gradientsMapFromGetGradientsMethod, weaponIDEnergyMap * energies)
{
	if ((!gradientsMapFromGetGradientsMethod) || (!energies))
	{
		return;
	}
	droneMissileLauncherPEnergyStatePPair dml;
	for (unsigned long loop1 = 0; NULL != (dml = this->droneMissileLaunchers(loop1)).first; loop1++)
	{
		weaponIDGradientMap::iterator litp1 = gradientsMapFromGetGradientsMethod->find(dml.first->getID());
		if (gradientsMapFromGetGradientsMethod->end() == litp1)
		{
			continue;
		}
		energies->insert(make_pair(dml.first->getID(), dml.second->energy + (unsigned long long)owningFortress->getEnergyGrowthByGradient(litp1->second)));
	}
	laserGunPEnergyStatePPair lg;
	for (unsigned long loop1 = 0; NULL != (lg = this->laserGuns(loop1)).first; loop1++)
	{
		weaponIDGradientMap::iterator litp1 = gradientsMapFromGetGradientsMethod->find(lg.first->getID());
		if (gradientsMapFromGetGradientsMethod->end() == litp1)
		{
			continue;
		}
		energies->insert(make_pair(lg.first->getID(), lg.second->energy + (unsigned long long)owningFortress->getEnergyGrowthByGradient(litp1->second)));
	}
};

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

void weaponsClass::getGradients(fortressClass * owningFortress, weaponIDGradientMap * gradients)
{
	if (!gradients)
	{
		return;
	}

	double maxTotalCharging = 0;
	droneMissileLauncherPEnergyStatePPair dml;
	for (unsigned long loop1 = 0; NULL != (dml = this->droneMissileLaunchers(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owningFortress, dml.first, dml.second))
		{
			maxTotalCharging += dml.first->actualCharging();
		}
	}
	laserGunPEnergyStatePPair lg;
	for (unsigned long loop1 = 0; NULL != (lg = this->laserGuns(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owningFortress, lg.first, lg.second))
		{
			maxTotalCharging += lg.first->actualCharging();
		}
	}
	double chargingRatio = min((double)1, this->narrowCharging_ / maxTotalCharging);

	for (unsigned long loop1 = 0; NULL != (dml = this->droneMissileLaunchers(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owningFortress, dml.first, dml.second))
		{
			gradients->insert(make_pair(dml.first->getID(), chargingRatio * dml.first->actualCharging()));
		}
		else
		{
			gradients->insert(make_pair(dml.first->getID(), (double)0));
		}
	}
	for (unsigned long loop1 = 0; NULL != (lg = this->laserGuns(loop1)).first; loop1++)
	{
		if (this->isWeaponCharging(owningFortress, lg.first, lg.second))
		{
			gradients->insert(make_pair(lg.first->getID(), chargingRatio * lg.first->actualCharging()));
		}
		else
		{
			gradients->insert(make_pair(lg.first->getID(), (double)0));
		}
	}
};

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

unsigned long long weaponsClass::repairingAndroidsRequired()
{
	unsigned long long result  = 0;
	if (0 < this->weaponEnergyCircuit()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->weaponEnergyCircuit()->getSize());
	}
	result += this->getMaxRepairingMechanicsBySize(this->droneMissiles()->getSize()) * this->droneMissiles()->getDamaged();
	for (unsigned long loop1 = 0; loop1 < droneMissileLaunchersIDs_.size(); loop1++)
	{
		if (0 < this->droneMissileLaunchersOnly(loop1)->getDamage())
		{
			result += this->getMaxRepairingMechanicsBySize(this->droneMissileLaunchersOnly(loop1)->getSize());
		}
	}
	for (unsigned long loop1 = 0; loop1 < laserGunsIDs_.size(); loop1++)
	{
		if (0 < this->laserGunsOnly(loop1)->getDamage())
		{
			result += this->getMaxRepairingMechanicsBySize(this->laserGunsOnly(loop1)->getSize());
		}
	}
	return result;
};

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

void weaponsClass::androidsDistribution(unsigned long long &cirPts, unsigned long long &droPts, vector<unsigned long long> &lauPts, vector<unsigned long long> &gunPts, unsigned long androidsPower)
{
	unsigned long long cirReq        = 0;
	unsigned long long droReq        = 0;
	unsignedLongLongVector lauReq;
	unsignedLongLongVector gunReq;
	lauReq.resize(this->droneMissileLaunchersIDs_.size(), 0);
	gunReq.resize(this->laserGunsIDs_.size(), 0);
	if (0 < this->weaponEnergyCircuit()->getDamage())
	{
		cirReq += this->getMaxRepairingMechanicsBySize(this->weaponEnergyCircuit()->getSize());
	}
	droReq += this->getMaxRepairingMechanicsBySize(this->droneMissiles()->getSize()) * this->droneMissiles()->getDamaged();
	for (unsigned long loop1 = 0; loop1 < this->droneMissileLaunchersIDs_.size(); loop1++)
	{
		if (0 < this->droneMissileLaunchersOnly(loop1)->getDamage())
		{
			lauReq[loop1] += this->getMaxRepairingMechanicsBySize(this->droneMissileLaunchersOnly(loop1)->getSize());
		}
	}
	for (unsigned long loop1 = 0; loop1 < this->laserGunsIDs_.size(); loop1++)
	{
		if (0 < this->laserGunsOnly(loop1)->getDamage())
		{
			gunReq[loop1] += this->getMaxRepairingMechanicsBySize(this->laserGunsOnly(loop1)->getSize());
		}
	}
	unsigned long long     cirGot = 0;
	unsigned long long     droGot = 0;
	unsignedLongLongVector lauGot;
	unsignedLongLongVector gunGot;
	lauGot.resize(this->droneMissileLaunchersIDs_.size(), 0);
	gunGot.resize(this->laserGunsIDs_.size(), 0);
	stacksAndLimits piles;
	piles.push_back(make_pair(&cirGot, cirReq));
	piles.push_back(make_pair(&droGot, droReq));
	for (unsigned long loop1 = 0; loop1 < droneMissileLaunchersIDs_.size(); loop1++)
	{
		piles.push_back(make_pair(&(lauGot[loop1]), lauReq[loop1]));
	}
	for (unsigned long loop1 = 0; loop1 < laserGunsIDs_.size(); loop1++)
	{
		piles.push_back(make_pair(&(gunGot[loop1]), gunGot[loop1]));
	}
	divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	                       cirPts    = (unsigned long long)cirGot * (unsigned long long)androidsPower;
						   droPts    = (unsigned long long)droGot * (unsigned long long)androidsPower;
						   lauPts;
						   gunPts;
	lauPts.resize(this->droneMissileLaunchersIDs_.size(), 0);
	gunPts.resize(this->laserGunsIDs_.size(), 0);
	for (unsigned long loop1 = 0; loop1 < droneMissileLaunchersIDs_.size(); loop1++)
	{
		lauPts[loop1] = (unsigned long long)lauGot[loop1] * (unsigned long long)androidsPower;
	}
	for (unsigned long loop1 = 0; loop1 < laserGunsIDs_.size(); loop1++)
	{
		gunPts[loop1] = (unsigned long long)gunGot[loop1] * (unsigned long long)androidsPower;
	}
};

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

void weaponsClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long     cirPts    = 0;
	unsigned long long     droPts    = 0;
	unsignedLongLongVector lauPts;
	unsignedLongLongVector gunPts;
	lauPts.resize(this->droneMissileLaunchersIDs_.size(), 0);
	gunPts.resize(this->laserGunsIDs_.size(), 0);
	this->androidsDistribution(cirPts, droPts, lauPts, gunPts, androidsPower);
	this->weaponEnergyCircuit()->repair(cirPts * seconds);
	this->droneMissiles()->repair      (droPts * seconds);
	for (unsigned long loop1 = 0; loop1 < droneMissileLaunchersIDs_.size(); loop1++)
	{
		this->droneMissileLaunchersOnly(loop1)->repair(lauPts[loop1] * seconds);
	}
	for (unsigned long loop1 = 0; loop1 < laserGunsIDs_.size(); loop1++)
	{
		this->laserGunsOnly(loop1)->repair            (gunPts[loop1] * seconds);
	}
};

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

unsigned long long weaponsClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long     cirPts    = 0;
	unsigned long long     droPts    = 0;
	unsignedLongLongVector lauPts;
	unsignedLongLongVector gunPts;
	lauPts.resize(this->droneMissileLaunchersIDs_.size(), 0);
	gunPts.resize(this->laserGunsIDs_.size(), 0);
	this->androidsDistribution(cirPts, droPts, lauPts, gunPts, androidsPower);
	unsigned long long secondsToCir  = maxSecondsToChange;
	unsigned long long secondsToDro  = maxSecondsToChange;
	if (0 < cirPts)
	{
		secondsToCir = ullUpRoundDiv(this->weaponEnergyCircuit()->pointsToCheckpoint(), cirPts);
	}
	if (0 < droPts)
	{
		secondsToDro = ullUpRoundDiv(this->droneMissiles()->pointsToCheckpoint(), droPts);
	}
	unsigned long long result = min(maxSecondsToChange, min(secondsToCir, secondsToDro));
	for (unsigned long loop1 = 0; loop1 < droneMissileLaunchersIDs_.size(); loop1++)
	{
		if (0 < lauPts[loop1])
		{
			result = min(result, ullUpRoundDiv(this->droneMissileLaunchersOnly(loop1)->pointsToCheckpoint(), lauPts[loop1]));
		}
	}
	for (unsigned long loop1 = 0; loop1 < laserGunsIDs_.size(); loop1++)
	{
		if (0 < gunPts[loop1])
		{
			result = min(result, ullUpRoundDiv(this->laserGunsOnly(loop1)->pointsToCheckpoint(), gunPts[loop1]));
		}
	}
	return result;
};

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

transportBeamGeneratorClass * transportBeamClass::transportBeamGenerator()
{
	if (transportBeamGeneratorClass * result = actx->cacheItemsList.getItem<transportBeamGeneratorClass>(transportBeamGeneratorID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullTransportBeamGeneratorClass>(PATTERN_ID_TRANSPORT_BEAM_GENERATOR);
	}
};

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

void transportBeamClass::annihilate()
{
	if (this->avalTransportBeamGenerator())
	{
		actx->cacheItemsList.deleteItem(this->transportBeamGeneratorID_);
		this->transportBeamGeneratorID_ = NOT_VALID_ID;
	}
};

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

unsigned long long transportBeamClass::getTransportBeamWeight()
{
	return (unsigned long long)transportBeamGenerator()->getWeight();
};

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

unsigned long long transportBeamClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->transportBeamGenerator()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->transportBeamGenerator()->getSize());
	}
	return result;
};

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

void transportBeamClass::androidsDistribution(unsigned long long &tbmPts, unsigned long androidsPower)
{
	unsigned long long tbmReq        = 0;
	if (0 < this->transportBeamGenerator()->getDamage())
	{
		tbmReq += this->getMaxRepairingMechanicsBySize(this->transportBeamGenerator()->getSize());
	}
	unsigned long long tbmGot        = min(tbmReq, this->androidsAssignment.assignedDroids);
	                   tbmPts        = (unsigned long long)tbmGot * (unsigned long long)androidsPower;
};

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

void transportBeamClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long tbmPts        = 0;
	this->androidsDistribution(tbmPts, androidsPower);
	this->transportBeamGenerator()->repair(tbmPts * seconds);
};

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

unsigned long long transportBeamClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long tbmPts        = 0;
	this->androidsDistribution(tbmPts, androidsPower);
	if (0 < tbmPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->transportBeamGenerator()->pointsToCheckpoint(), tbmPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

magneticalCollectorsOfPlasmaClass * miningDevicesClass::magneticalCollectorsOfPlasma()
{
	if (magneticalCollectorsOfPlasmaClass * result = actx->cacheItemsList.getItem<magneticalCollectorsOfPlasmaClass>(magneticalCollectorsOfPlasmaID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullMagneticalCollectorsOfPlasmaClass>(PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA);
	}
};

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

submersibleFiltrationTankClass * miningDevicesClass::submersibleFiltrationTank()
{ 
	if (submersibleFiltrationTankClass * result = actx->cacheItemsList.getItem<submersibleFiltrationTankClass>(submersibleFiltrationTankID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullSubmersibleFiltrationTankClass>(PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK);
	}
};

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

submarineMiningMachineClass * miningDevicesClass::submarineMiningMachine()
{
	if (submarineMiningMachineClass * result = actx->cacheItemsList.getItem<submarineMiningMachineClass>(submarineMiningMachineID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullSubmarineMiningMachineClass>(PATTERN_ID_SUBMARINE_MINING_MACHINE);
	}
};

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

undergroundDrillingMachineClass * miningDevicesClass::undergroundDrillingMachine()
{
	if (undergroundDrillingMachineClass * result = actx->cacheItemsList.getItem<undergroundDrillingMachineClass>(undergroundDrillingMachineID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullUndergroundDrillingMachineClass>(PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE);
	}
};

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

void miningDevicesClass::annihilate()
{
	if (this->avalMagneticalCollectorsOfPlasma())
	{
		actx->cacheItemsList.deleteItem(this->magneticalCollectorsOfPlasmaID_);
		this->magneticalCollectorsOfPlasmaID_ = NOT_VALID_ID;
	}
	if (this->avalSubmersibleFiltrationTank())
	{
		actx->cacheItemsList.deleteItem(this->submersibleFiltrationTankID_);
		this->submersibleFiltrationTankID_ = NOT_VALID_ID;
	}
	if (this->submarineMiningMachine())
	{
		actx->cacheItemsList.deleteItem(this->submarineMiningMachineID_);
		this->submarineMiningMachineID_ = NOT_VALID_ID;
	}
	if (this->undergroundDrillingMachine())
	{
		actx->cacheItemsList.deleteItem(this->undergroundDrillingMachineID_);
		this->undergroundDrillingMachineID_ = NOT_VALID_ID;
	}
};

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

unsigned long long miningDevicesClass::getMiningDevicesWeight()
{
	return (unsigned long long)magneticalCollectorsOfPlasma()->getAllStackedItemsTotalWeight() +
		   (unsigned long long)submersibleFiltrationTank()->getAllStackedItemsTotalWeight()    +
		   (unsigned long long)submarineMiningMachine()->getAllStackedItemsTotalWeight()       +
		   (unsigned long long)undergroundDrillingMachine()->getAllStackedItemsTotalWeight();
};

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

unsigned long long miningDevicesClass::getMiningDevicesSize()
{
	return (unsigned long long)magneticalCollectorsOfPlasma()->getAllStackedItemsTotalSize() +
		   (unsigned long long)submersibleFiltrationTank()->getAllStackedItemsTotalSize()    +
		   (unsigned long long)submarineMiningMachine()->getAllStackedItemsTotalSize()       +
		   (unsigned long long)undergroundDrillingMachine()->getAllStackedItemsTotalSize();
};

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

unsigned long long miningDevicesClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	result += this->getMaxRepairingMechanicsBySize(this->magneticalCollectorsOfPlasma()->getSize()) * this->magneticalCollectorsOfPlasma()->getDamaged();
	result += this->getMaxRepairingMechanicsBySize(this->submarineMiningMachine()->getSize())       * this->submarineMiningMachine()->getDamaged()      ;
	result += this->getMaxRepairingMechanicsBySize(this->submersibleFiltrationTank()->getSize())    * this->submersibleFiltrationTank()->getDamaged()   ;
	result += this->getMaxRepairingMechanicsBySize(this->undergroundDrillingMachine()->getSize())   * this->undergroundDrillingMachine()->getDamaged()  ;
	return result;
};

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

void miningDevicesClass::androidsDistribution(unsigned long long &mcpPts, unsigned long long &sftPts, unsigned long long &smmPts, unsigned long long &udmPts, unsigned long androidsPower)
{
	unsigned long long mcpReq        = 0;
	unsigned long long sftReq        = 0;
	unsigned long long smmReq        = 0;
	unsigned long long udmReq        = 0;
	mcpReq += this->getMaxRepairingMechanicsBySize(this->magneticalCollectorsOfPlasma()->getSize()) * this->magneticalCollectorsOfPlasma()->getDamaged();
	sftReq += this->getMaxRepairingMechanicsBySize(this->submersibleFiltrationTank()->getSize())    * this->submersibleFiltrationTank()->getDamaged()   ;
	smmReq += this->getMaxRepairingMechanicsBySize(this->submarineMiningMachine()->getSize())       * this->submarineMiningMachine()->getDamaged()      ;
	udmReq += this->getMaxRepairingMechanicsBySize(this->undergroundDrillingMachine()->getSize())   * this->undergroundDrillingMachine()->getDamaged()  ;
	unsigned long long mcpGot        = 0;
	unsigned long long sftGot        = 0;
	unsigned long long smmGot        = 0;
	unsigned long long udmGot        = 0;
	if (this->androidsAssignment.assignedDroids < mcpReq + sftReq + smmReq + udmReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&mcpGot, mcpReq));
		piles.push_back(make_pair(&sftGot, sftReq));
		piles.push_back(make_pair(&smmGot, smmReq));
		piles.push_back(make_pair(&udmGot, udmReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		mcpGot                       = mcpReq;
		sftGot                       = sftReq;
		smmGot                       = smmReq;
		udmGot                       = udmReq;
	}
	                   mcpPts        = (unsigned long long)mcpGot * (unsigned long long)androidsPower;
	                   sftPts        = (unsigned long long)sftGot * (unsigned long long)androidsPower;
	                   smmPts        = (unsigned long long)smmGot * (unsigned long long)androidsPower;
	                   udmPts        = (unsigned long long)udmGot * (unsigned long long)androidsPower;
};

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

void miningDevicesClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mcpPts        = 0;
	unsigned long long sftPts        = 0;
	unsigned long long smmPts        = 0;
	unsigned long long udmPts        = 0;
	this->androidsDistribution(mcpPts, sftPts, smmPts, udmPts, androidsPower);
	this->magneticalCollectorsOfPlasma()->repair(mcpPts * seconds);
	this->submersibleFiltrationTank()->repair   (sftPts * seconds);
	this->submarineMiningMachine()->repair      (smmPts * seconds);
	this->undergroundDrillingMachine()->repair  (udmPts * seconds);
};

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

unsigned long long miningDevicesClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mcpPts        = 0;
	unsigned long long sftPts        = 0;
	unsigned long long smmPts        = 0;
	unsigned long long udmPts        = 0;
	this->androidsDistribution(mcpPts, sftPts, smmPts, udmPts, androidsPower);
	unsigned long long secondsToMcp  = maxSecondsToChange;
	unsigned long long secondsToSft  = maxSecondsToChange;
	unsigned long long secondsToSmm  = maxSecondsToChange;
	unsigned long long secondsToUdm  = maxSecondsToChange;
	if (0 < mcpPts)
	{
		secondsToMcp = ullUpRoundDiv(this->magneticalCollectorsOfPlasma()->pointsToCheckpoint(), mcpPts);
	}
	if (0 < sftPts)
	{
		secondsToSft = ullUpRoundDiv(this->submersibleFiltrationTank()->pointsToCheckpoint(), sftPts);
	}
	if (0 < smmPts)
	{
		secondsToSmm = ullUpRoundDiv(this->submarineMiningMachine()->pointsToCheckpoint(), smmPts);
	}
	if (0 < udmPts)
	{
		secondsToUdm = ullUpRoundDiv(this->undergroundDrillingMachine()->pointsToCheckpoint(), udmPts);
	}
	return min(maxSecondsToChange,
		   min(secondsToMcp,
		   min(secondsToSft, 
		   min(secondsToSmm,
		       secondsToUdm))));	
};

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

void probeDevicesClass::annihilate()
{
	if (this->avalProbes())
	{
		for (dtIdentifierDeque::iterator litp1 = this->probesIDs_.begin(); this->probesIDs_.end() != litp1; litp1++)
		{
			actx->cacheItemsList.deleteItem(*litp1);
		}
		this->probesIDs_.clear();
	}
};

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

unsigned long long probeDevicesClass::getProbeDevicesWeight()
{
	unsigned long long probesWeight = 0;

	probeClass * p;
	for (unsigned long loop1 = 0; NULL != (p = probes(loop1)); loop1++)
	{
		probesWeight += p->getWeight();
	}

	return (unsigned long long)probesWeight;
};

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

unsigned long long probeDevicesClass::getProbeDevicesSize()
{
	unsigned long long probesSize = 0;

	probeClass * p;
	for (unsigned long loop1 = 0; NULL != (p = probes(loop1)); loop1++)
	{
		probesSize += p->getSize();
	}

	return (unsigned long long)probesSize;
};

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

unsigned long long probeDevicesClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	for (unsigned long loop1 = 0; loop1 < probesIDs_.size(); loop1++)
	{
		if (0 < this->probes(loop1)->getDamage())
		{
			result += this->getMaxRepairingMechanicsBySize(this->probes(loop1)->getSize());
		}
	}
	return result;
};

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

void probeDevicesClass::androidsDistribution(vector<unsigned long long> &proPts, unsigned long androidsPower)
{
	unsignedLongLongVector proReq;
	proReq.resize(this->probesIDs_.size(), 0);
	for (unsigned long loop1 = 0; loop1 < this->probesIDs_.size(); loop1++)
	{
		if (0 < this->probes(loop1)->getDamage())
		{
			proReq[loop1] += this->getMaxRepairingMechanicsBySize(this->probes(loop1)->getSize());
		}
	}
	unsignedLongLongVector proGot;
	proGot.resize(this->probesIDs_.size(), 0);
	stacksAndLimits piles;
	for (unsigned long loop1 = 0; loop1 < probesIDs_.size(); loop1++)
	{
		piles.push_back(make_pair(&(proGot[loop1]), proReq[loop1]));
	}
	divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	                       proPts;
	proPts.resize(this->probesIDs_.size(), 0);
	for (unsigned long loop1 = 0; loop1 < probesIDs_.size(); loop1++)
	{
		proPts[loop1] = (unsigned long long)proGot[loop1] * (unsigned long long)androidsPower;
	}
};

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

void probeDevicesClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsignedLongLongVector proPts;
	proPts.resize(this->probesIDs_.size(), 0);
	this->androidsDistribution(proPts, androidsPower);
	for (unsigned long loop1 = 0; loop1 < probesIDs_.size(); loop1++)
	{
		this->probes(loop1)->repair(proPts[loop1] * seconds);
	}
};

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

unsigned long long probeDevicesClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);	
	unsignedLongLongVector proPts;
	proPts.resize(this->probesIDs_.size(), 0);
	this->androidsDistribution(proPts, androidsPower);
	unsigned long long result = maxSecondsToChange;
	for (unsigned long loop1 = 0; loop1 < probesIDs_.size(); loop1++)
	{
		if (0 < proPts[loop1])
		{
			result = min(result, ullUpRoundDiv(this->probes(loop1)->pointsToCheckpoint(), proPts[loop1]));
		}
	}
	return result;
};

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

highResolutionSensorsClass * sensorsClass::highResolutionSensors()
{
	if (highResolutionSensorsClass * result = actx->cacheItemsList.getItem<highResolutionSensorsClass>(highResolutionSensorsID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullHighResolutionSensorsClass>(PATTERN_ID_HIGH_RESOLUTION_SENSORS);
	}
};

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

longRangeSensorsClass * sensorsClass::longRangeSensors()
{
	if (longRangeSensorsClass * result = actx->cacheItemsList.getItem<longRangeSensorsClass>(longRangeSensorsID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullLongRangeSensorsClass>(PATTERN_ID_LONG_RANGE_SENSORS);
	}
};

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

void sensorsClass::annihilate()
{
	if (this->avalHighResolutionSensors())
	{
		actx->cacheItemsList.deleteItem(this->highResolutionSensorsID_);
		this->highResolutionSensorsID_ = NOT_VALID_ID;
	}
	if (this->avalLongRangeSensors())
	{
		actx->cacheItemsList.deleteItem(this->longRangeSensorsID_);
		this->longRangeSensorsID_ = NOT_VALID_ID;
	}
};

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

unsigned long long sensorsClass::getSensorsWeight()
{
	return (unsigned long long)highResolutionSensors()->getWeight() +
		   (unsigned long long)longRangeSensors()->getWeight();
};

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

unsigned long long sensorsClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->highResolutionSensors()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->highResolutionSensors()->getSize());
	}
	if (0 < this->longRangeSensors()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->longRangeSensors()->getSize());
	}
	return result;
};

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

void sensorsClass::androidsDistribution(unsigned long long &hrsPts, unsigned long long &lrsPts, unsigned long androidsPower)
{
	unsigned long long hrsReq        = 0;
	unsigned long long lrsReq        = 0;
	if (0 < this->highResolutionSensors()->getDamage())
	{
		hrsReq += this->getMaxRepairingMechanicsBySize(this->highResolutionSensors()->getSize());
	}
	if (0 < this->longRangeSensors()->getDamage())
	{
		lrsReq += this->getMaxRepairingMechanicsBySize(this->longRangeSensors()->getSize());
	}
	unsigned long long hrsGot        = 0;
	unsigned long long lrsGot        = 0;
	if (this->androidsAssignment.assignedDroids < hrsReq + lrsReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&hrsGot, hrsReq));
		piles.push_back(make_pair(&lrsGot, lrsReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		hrsGot                       = hrsReq;
		lrsGot                       = lrsReq;
	}
	                   hrsPts        = (unsigned long long)hrsGot * (unsigned long long)androidsPower;
					   lrsPts        = (unsigned long long)lrsGot * (unsigned long long)androidsPower;
};

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

void sensorsClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long hrsPts        = 0;
	unsigned long long lrsPts        = 0;
	this->androidsDistribution(hrsPts, lrsPts, androidsPower);
	this->highResolutionSensors()->repair(hrsPts * seconds);
	this->longRangeSensors()->repair     (lrsPts * seconds);
};

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

unsigned long long sensorsClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long hrsPts        = 0;
	unsigned long long lrsPts        = 0;
	this->androidsDistribution(hrsPts, lrsPts, androidsPower);
	unsigned long long secondsToHrs  = maxSecondsToChange;
	unsigned long long secondsToLrs  = maxSecondsToChange;
	if (0 < hrsPts)
	{
		secondsToHrs = ullUpRoundDiv(this->highResolutionSensors()->pointsToCheckpoint(), hrsPts);
	}
	if (0 < lrsPts)
	{
		secondsToLrs = ullUpRoundDiv(this->longRangeSensors()->pointsToCheckpoint(), lrsPts);
	}
	return min(maxSecondsToChange, min(secondsToHrs, secondsToLrs));
};

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

cloakingDeviceClass * cloakingClass::cloakingDevice()
{
	if (cloakingDeviceClass * result = actx->cacheItemsList.getItem<cloakingDeviceClass>(cloakingDeviceID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullCloakingDeviceClass>(PATTERN_ID_CLOAKING_DEVICE);
	}
};

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

void cloakingClass::annihilate()
{
	if (this->avalCloakingDevice())
	{
		actx->cacheItemsList.deleteItem(this->cloakingDeviceID_);
		this->cloakingDeviceID_ = NOT_VALID_ID;
	}
};

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

unsigned long long cloakingClass::getCloakingWeight()
{
	return (unsigned long long)cloakingDevice()->getWeight();
};

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

unsigned long long cloakingClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->cloakingDevice()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->cloakingDevice()->getSize());
	}
	return result;
};

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

void cloakingClass::androidsDistribution(unsigned long long &cloPts, unsigned long androidsPower)
{
	unsigned long long cloReq        = 0;
	if (0 < this->cloakingDevice()->getDamage())
	{
		cloReq += this->getMaxRepairingMechanicsBySize(this->cloakingDevice()->getSize());
	}
	unsigned long long cloGot        = min(cloReq, this->androidsAssignment.assignedDroids);
	                   cloPts        = (unsigned long long)cloGot * (unsigned long long)androidsPower;
};

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

void cloakingClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long cloPts        = 0;
	this->androidsDistribution(cloPts, androidsPower);
	this->cloakingDevice()->repair(cloPts * seconds);
};

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

unsigned long long cloakingClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long cloPts        = 0;
	this->androidsDistribution(cloPts, androidsPower);
	if (0 < cloPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->cloakingDevice()->pointsToCheckpoint(), cloPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

unsigned long crewClass::getEffectiveCountOf(unsigned short position)
{
	if (CREW_PASSENGER == position)
	{
		return 0;
	}

	if (CREW_CAPITAN == position)
	{
		return this->ableCrew_[position];
	}
	if (CREW_OFFICER == position)
	{
		return this->ableCrew_[position];
	}

	unsigned long realAbles     = this->ableCrew_[position    ];
	unsigned long officersAbles = this->ableCrew_[CREW_OFFICER];
	unsigned long capitanAlbe   = this->ableCrew_[CREW_CAPITAN];

	double capitanRatio = (double)0.5;
	if (0 < capitanAlbe)
	{
		capitanRatio = (double)1;
	}
	else
	{
		if (0 < officersAbles)
		{
			capitanRatio = (double)0.75;
			officersAbles--;
		}
	}

	return ulUpRound(((double)realAbles + (double)OFFICERS_EFFECTIVITY * (double)officersAbles) * (double)capitanRatio);
};

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

unsigned long crewClass::getTotalCrewCount()
{
	unsigned long peopleCount = 0;

	for (unsigned long loop1 = 0; loop1 < ableCrew_.size(); loop1++)
	{
		peopleCount += ableCrew_[loop1];
	}

	for (unsigned long loop1 = 0; loop1 < woundedCrew_.size(); loop1++)
	{
		peopleCount += woundedCrew_[loop1];
	}

	return peopleCount;
};

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

void crewClass::acceptSomeNewAbles(fortressClass * owningFortress, unsigned short position, unsigned long & acceptedCount)
{
	unsigned long crewTotalCount     = this->getTotalCrewCount();
	unsigned long accommodationSpace = owningFortress->accommodations.getLivingSpaces();
	unsigned long lifeSupportSpace   = owningFortress->otherEquipment.lifeSupport()->actualCapacity();
	unsigned long maxLivingSpace     = min(accommodationSpace, lifeSupportSpace);
	unsigned long freeLivingSpace    = ulSafeSub(maxLivingSpace, crewTotalCount);
	if (CREW_CAPITAN == position)
	{
		acceptedCount = min(1 - min(1, this->ableCrew_[position] + this->woundedCrew_[position]), acceptedCount);
	}
	else
	{
		acceptedCount = min(acceptedCount, freeLivingSpace);
	}
	this->ableCrew_[position] += acceptedCount;
};

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

void crewClass::acceptSomeNewWounded(fortressClass * owningFortress, unsigned short position, unsigned long & acceptedCount)
{
	unsigned long crewTotalCount     = this->getTotalCrewCount();
	unsigned long accommodationSpace = owningFortress->accommodations.getLivingSpaces();
	unsigned long lifeSupportSpace   = owningFortress->otherEquipment.lifeSupport()->actualCapacity();
	unsigned long maxLivingSpace     = min(accommodationSpace, lifeSupportSpace);
	unsigned long freeLivingSpace    = ulSafeSub(maxLivingSpace, crewTotalCount);
	if (CREW_CAPITAN == position)
	{
		acceptedCount = min(1 - min(1, this->ableCrew_[position] + this->woundedCrew_[position]), acceptedCount);
	}
	else
	{
		acceptedCount = min(acceptedCount, freeLivingSpace);
	}
	this->woundedCrew_[position] += acceptedCount;
};

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

unsigned long long crewClass::getCrewWeight()
{
	return (unsigned long long)getTotalCrewCount() * (unsigned long long)PEOPLE_WEIGHT;
};

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

void crewClass::reasonableSacrifice(unsigned long killed)
{
	for (unsigned long loop1 = 0; loop1 < woundedCrew_.size(); loop1++)
	{
		if (killed > woundedCrew_[loop1])
		{
			killed              -= woundedCrew_[loop1];
			woundedCrew_[loop1]  = 0;
		}
		else
		{
			woundedCrew_[loop1] -= killed;
			killed               = 0;
			break;
		}
	}
	for (unsigned long loop1 = 0; loop1 < ableCrew_.size(); loop1++)
	{
		if (killed > ableCrew_[loop1])
		{
			killed           -= ableCrew_[loop1];
			ableCrew_[loop1]  = 0;
		}
		else
		{
			ableCrew_[loop1] -= killed;
			killed            = 0;
			break;
		}
	}
};

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

void crewClass::healingPhase()
{
	unsigned long crewCount    = this->getTotalCrewCount();
	unsigned long woundedCount = sumWholeContainer<unsignedLongVector, unsigned long>(this->woundedCrew_);
	if (!(0 < woundedCount))
	{
		return;
	}
	unsigned long healingDone  = max(1, (unsigned long)(SELF_HEALING * (double)woundedCount)) + DOC_CAN_HEAL * this->getAblesCountOf(CREW_DOCTOR);
	for (unsigned short loop1 = 0; loop1 < CREW_COUNT_TOTAL; loop1++)
	{
		unsigned long healingMax  = min(healingDone, this->woundedCrew_[loop1]);
		healingDone              -= healingMax;
		this->healSome(loop1, healingMax);
	}
};

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

void crewClass::dropPassengers(fortressClass * owningFortress, unsigned long count, unsigned long & VIPPayers, unsigned long & commonPayers, unsigned long & poorPayers, unsigned long & miserablePayers)
{
	unsigned long freeVIPAcc;
	unsigned long freeCommonAcc;
	unsigned long freePoorAcc;
	unsigned long freeMiserableAcc;
	owningFortress->accommodations.getFreeAccomodationUnits(owningFortress, freeVIPAcc, freeCommonAcc, freePoorAcc, freeMiserableAcc, 1);

	if (count <= this->woundedCrew_[CREW_PASSENGER])
	{
		VIPPayers                           = 0;
		commonPayers                        = 0;
		poorPayers                          = 0;
		miserablePayers                     = 0;
		this->woundedCrew_[CREW_PASSENGER] -= count;
	}
	else
	{
		count                              -= this->woundedCrew_[CREW_PASSENGER];
		this->woundedCrew_[CREW_PASSENGER]  = 0;
		count                               = min(count, this->ableCrew_[CREW_PASSENGER]);
		if ((freeVIPAcc + freeCommonAcc + freePoorAcc + freeMiserableAcc) < (this->ableCrew_[CREW_PASSENGER]))
		{
			errLogicalError("Not accomodated crew (ID %u).", (unsigned long long)owningFortress->getID());
			this->ableCrew_[CREW_PASSENGER] = min(this->ableCrew_[CREW_PASSENGER], freeVIPAcc + freeCommonAcc + freePoorAcc + freeMiserableAcc);
		}
		miserablePayers                 = min(count, freeMiserableAcc);
		count                           = ulSafeSub(count                          , miserablePayers);
		this->ableCrew_[CREW_PASSENGER] = ulSafeSub(this->ableCrew_[CREW_PASSENGER], miserablePayers);
		poorPayers                      = min(count, freePoorAcc);
		count                           = ulSafeSub(count                          , poorPayers     );
		this->ableCrew_[CREW_PASSENGER] = ulSafeSub(this->ableCrew_[CREW_PASSENGER], poorPayers     );
		commonPayers                    = min(count, freeCommonAcc);
		count                           = ulSafeSub(count                          , commonPayers   );
		this->ableCrew_[CREW_PASSENGER] = ulSafeSub(this->ableCrew_[CREW_PASSENGER], commonPayers   );
		VIPPayers                       = min(count, freeVIPAcc);
		count                           = ulSafeSub(count                          , VIPPayers      );
		this->ableCrew_[CREW_PASSENGER] = ulSafeSub(this->ableCrew_[CREW_PASSENGER], VIPPayers      );
	}
};

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

void accommodationsClass::divideOneCrewType(unsigned long count, unsigned short preferedAccomodationID, unsigned long & apartments, unsigned long & rooms, unsigned long & cabins, unsigned long & warehouses)
{
	vector<unsigned long *> accomodations;
	if (ID_OF_APARTMENTS == preferedAccomodationID)
	{
		accomodations.push_back(&apartments);
		accomodations.push_back(&rooms     );
		accomodations.push_back(&cabins    );
		accomodations.push_back(&warehouses);
	}
	if (ID_OF_ROOMS == preferedAccomodationID)
	{
		accomodations.push_back(&rooms     );
		accomodations.push_back(&apartments);
		accomodations.push_back(&cabins    );
		accomodations.push_back(&warehouses);
	}
	if (ID_OF_CABINS == preferedAccomodationID)
	{
		accomodations.push_back(&cabins    );
		accomodations.push_back(&rooms     );
		accomodations.push_back(&warehouses);
		accomodations.push_back(&apartments);
	}
	if (ID_OF_WAREHOUSES == preferedAccomodationID)
	{
		accomodations.push_back(&warehouses);
		accomodations.push_back(&cabins    );
		accomodations.push_back(&rooms     );
		accomodations.push_back(&apartments);
	}
	for (unsigned long loop1 = 0; loop1 < accomodations.size(); loop1++)
	{
		unsigned long transfer   = min(count, (*(accomodations[loop1])));
		(*accomodations[loop1]) -= transfer;
		count                   -= transfer;
	}
};

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

void accommodationsClass::getFreeAccomodationUnits(fortressClass * owner, unsigned long & apartments, unsigned long & rooms, unsigned long & cabins, unsigned long & warehouses, bool skipPassengers)
{
	apartments = this->luxuryApartments_;
	rooms      = this->comfortableRooms_;
	cabins     = this->commonCabins_;
	warehouses = this->warehousesWithLifeSupport_;

	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_CAPITAN  ), ID_OF_APARTMENTS, apartments, rooms, cabins, warehouses);
	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_OFFICER  ), ID_OF_APARTMENTS, apartments, rooms, cabins, warehouses);
	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_SCIENTIST), ID_OF_ROOMS     , apartments, rooms, cabins, warehouses);
	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_PILOT    ), ID_OF_CABINS    , apartments, rooms, cabins, warehouses);
	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_ENGINEER ), ID_OF_CABINS    , apartments, rooms, cabins, warehouses);
	this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_DOCTOR   ), ID_OF_CABINS    , apartments, rooms, cabins, warehouses);
	if (!skipPassengers)
	{
		this->divideOneCrewType(owner->crew.getTotalCountOf(CREW_PASSENGER), ID_OF_APARTMENTS, apartments, rooms, cabins, warehouses);
	}
};

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

void accommodationsClass::addLuxuryApartments(fortressClass * constructingFortress, unsigned long & moreAccommodationUnits)
{
	unsigned long      pointsLeft       = constructingFortress->getFortressClass()->getAccomodationPointsTotal() - this->getConsumedPoints();
	unsigned long      maxUnitsByPoints = pointsLeft / POINTS_FOR_APARTMENT;
	unsigned long long sizeLeft         = constructingFortress->freeCapacity();
	unsigned long long maxUnitsBySize   = sizeLeft   / (unsigned long long)APARTMENT_SIZE;

	moreAccommodationUnits              = (unsigned long)min(min((unsigned long long)moreAccommodationUnits, (unsigned long long)maxUnitsByPoints), (unsigned long long)maxUnitsBySize);
	this->luxuryApartments_            += moreAccommodationUnits;
};

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

void accommodationsClass::addComfortableRooms(fortressClass * constructingFortress, unsigned long & moreAccommodationUnits)
{
	unsigned long      pointsLeft       = constructingFortress->getFortressClass()->getAccomodationPointsTotal() - this->getConsumedPoints();
	unsigned long      maxUnitsByPoints = pointsLeft / POINTS_FOR_ROOM;
	unsigned long long sizeLeft         = constructingFortress->freeCapacity();
	unsigned long long maxUnitsBySize   = sizeLeft   / (unsigned long long)ROOM_SIZE;

	moreAccommodationUnits              = (unsigned long)min(min((unsigned long long)moreAccommodationUnits, (unsigned long long)maxUnitsByPoints), (unsigned long long)maxUnitsBySize);
	this->comfortableRooms_            += moreAccommodationUnits;
};

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

void accommodationsClass::addCommonCabins(fortressClass * constructingFortress, unsigned long & moreAccommodationUnits)
{
	unsigned long      pointsLeft       = constructingFortress->getFortressClass()->getAccomodationPointsTotal() - this->getConsumedPoints();
	unsigned long      maxUnitsByPoints = pointsLeft / POINTS_FOR_CABIN;
	unsigned long long sizeLeft         = constructingFortress->freeCapacity();
	unsigned long long maxUnitsBySize   = sizeLeft   / (unsigned long long)CABIN_SIZE;

	moreAccommodationUnits              = (unsigned long)min(min((unsigned long long)moreAccommodationUnits, (unsigned long long)maxUnitsByPoints), (unsigned long long)maxUnitsBySize);
	this->commonCabins_                += moreAccommodationUnits;
};

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

void accommodationsClass::addWarehousesWithLifeSupport(fortressClass * constructingFortress, unsigned long & moreAccommodationUnits)
{
	unsigned long      pointsLeft       = constructingFortress->getFortressClass()->getAccomodationPointsTotal() - this->getConsumedPoints();
	unsigned long      maxUnitsByPoints = pointsLeft / POINTS_FOR_WAREHOUSE;
	unsigned long long sizeLeft         = constructingFortress->freeCapacity();
	unsigned long long maxUnitsBySize   = sizeLeft   / (unsigned long long)WAREHOUSE_SIZE;

	moreAccommodationUnits              = (unsigned long)min(min((unsigned long long)moreAccommodationUnits, (unsigned long long)maxUnitsByPoints), (unsigned long long)maxUnitsBySize);
	this->warehousesWithLifeSupport_ += moreAccommodationUnits;
};

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

unsigned long long accommodationsClass::getAccomodationsWeight()
{
	return 0; // patri do hmotnosti lodi ci zakladny
};

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

unsigned long long accommodationsClass::getAccomodationsSize()
{
	return (unsigned long long)luxuryApartments_          * (unsigned long long)APARTMENT_SIZE +
		   (unsigned long long)comfortableRooms_          * (unsigned long long)ROOM_SIZE      +
		   (unsigned long long)commonCabins_              * (unsigned long long)CABIN_SIZE     +
		   (unsigned long long)warehousesWithLifeSupport_ * (unsigned long long)WAREHOUSE_SIZE;
};

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

androidsClass * mechanicsClass::androids()
{
	if (androidsClass * result = actx->cacheItemsList.getItem<androidsClass>(androidsID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullAndroidsClass>(PATTERN_ID_ANDROIDS);
	}
};

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

void mechanicsClass::initRepairingVector(fortressClass * owningFortress)
{
	owningFortress->initRepairableSectionsVector(repairingVector_); 
};

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

void mechanicsClass::mountAndroids(androidsClass * pattern, unsigned long long count)
{
	if (pattern->isNull())
	{
		return;
	}
	if (this->nullAndroids())
	{
		this->androidsID_ = (actx->cacheItemsList).insertItem(pattern->createEmptyCopyOfItemOfTheSameClass());
		this->androidsPowerState.turnOn();
	}
	this->androids()->addWorking(count); 
}

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

void mechanicsClass::annihilate()
{
	if (this->avalAndroids())
	{
		actx->cacheItemsList.deleteItem(this->androidsID_);
		this->androidsID_ = NOT_VALID_ID;
	}
};

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

unsigned long long mechanicsClass::getMechanicsWeight()
{
	return (unsigned long long)androids()->getAllStackedItemsTotalWeight();
};

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

unsigned long long mechanicsClass::getMechanicsSize()
{
	return (unsigned long long)androids()->getAllStackedItemsTotalSize();
};

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

void mechanicsClass::repairingPhase(fortressClass * owningFortress, unsigned long long secondsFromTheLastUpdate)
{
	for (unsigned long loop1 = 0; loop1 < repairingVector_.size(); loop1++)
	{
		repairingVector_[loop1]->repair(owningFortress, secondsFromTheLastUpdate);
	}
};

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

unsigned long long mechanicsClass::repairingDistribution(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	typedef pair  <fortressSectionClass *, unsigned long long> sectionPRequiringPair;
	typedef vector<sectionPRequiringPair                     > priorityClassVector;
	typedef vector<priorityClassVector                       > priorityVector;

	maxSecondsToChange = max(1, maxSecondsToChange);

	priorityVector priorities;
	priorities.resize(AA_MAX_PRIORITY + 1);
	for (unsigned long loop1 = 0; loop1 < priorities.size(); loop1++)
	{
		priorities[loop1].clear();
	}

	unsigned long long androidsRequiredForRepair = 0;
	for (unsigned long loop1 = 0; loop1 < repairingVector_.size(); loop1++)
	{
		unsigned long long reqAnd  = repairingVector_[loop1]->repairingAndroidsRequired();
		androidsRequiredForRepair += reqAnd;
		// STEPAN FIX - Tady je priorita 255, ale max ma byt 16! Pak to spadne, protoze je to neplatny index
		priorities[repairingVector_[loop1]->androidsAssignment.priority].push_back(make_pair(repairingVector_[loop1], reqAnd));
	}

	unsigned long long androidsRequiredForConstruction = 0;
	if (FT_BASE == owningFortress->getFortressType())
	{
		androidsRequiredForConstruction = ((baseClass *)(owningFortress))->hangarsPort.totalConstructingAndroidsRequired();
	}

	unsigned long long workingAndroids      = min(maxWorkingAndroids_, (unsigned long long)(androidsPowerState.getNarrowCharging() / androids()->actualConsumption(owningFortress->getFortressRealmID())));
	unsigned long long repairingAndroids    = min(workingAndroids, androidsRequiredForRepair      );
	unsigned long long constructingAndroids = min(workingAndroids, androidsRequiredForConstruction);
	if (workingAndroids < (repairingAndroids + constructingAndroids))
	{
		repairingAndroids    = min(repairingAndroids, maxRepairingAndroids_);
		constructingAndroids = workingAndroids - repairingAndroids;
	}
	actualConstructingAndroids_ = constructingAndroids;
	actualRepairingAndroids_    = 0;

	for (unsigned long loop1 = AA_MAX_PRIORITY; AA_MIN_PRIORITY <= loop1; loop1--)
	{
		unsigned long long requiredForThisPriority = 0;
		unsigned long long ratioForThisPriority    = 0;
		for (unsigned long loop2 = 0; loop2 < priorities[loop1].size(); loop2++)
		{
			requiredForThisPriority += ((priorities[loop1])[loop2]).second;
			ratioForThisPriority    += ((priorities[loop1])[loop2]).first->androidsAssignment.ratio;
		}
		if (repairingAndroids < requiredForThisPriority)
		{
			ratioForThisPriority = max(1, ratioForThisPriority);
			for (unsigned long loop2 = 0; loop2 < priorities[loop1].size(); loop2++)
			{
				unsigned long long assigned = min(((priorities[loop1])[loop2]).second, ((priorities[loop1])[loop2]).first->androidsAssignment.ratio / ratioForThisPriority);
				((priorities[loop1])[loop2]).first->androidsAssignment.assignedDroids  = assigned;
				repairingAndroids                                                     -= assigned;
				actualRepairingAndroids_                                              += assigned;
			}
			for (unsigned long loop2 = 0; loop2 < priorities[loop1].size(); loop2++)
			{
				((priorities[loop1])[loop2]).first->androidsAssignment.assignedDroids++;
				actualRepairingAndroids_++;
				if (0 == (--repairingAndroids))
				{
					break;
				}
			}
			break;
		}
		else
		{
			repairingAndroids -= requiredForThisPriority;
			for (unsigned long loop2 = 0; loop2 < priorities[loop1].size(); loop2++)
			{
				((priorities[loop1])[loop2]).first->androidsAssignment.assignedDroids = ((priorities[loop1])[loop2]).second;
			}
			actualRepairingAndroids_ += requiredForThisPriority;
		}
	}

	for (unsigned long loop1 = 0; loop1 < repairingVector_.size(); loop1++)
	{
		maxSecondsToChange = min(maxSecondsToChange, repairingVector_[loop1]->secondsToChange(owningFortress, maxSecondsToChange));
	}

	return maxSecondsToChange;
};

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

unsigned long long mechanicsClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	result += this->getMaxRepairingMechanicsBySize(this->androids()->getSize()) * this->androids()->getDamaged();
	return result;
};

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

void mechanicsClass::androidsDistribution(unsigned long long &andPts, unsigned long androidsPower)
{
	unsigned long long andReq        = 0;
	andReq += this->getMaxRepairingMechanicsBySize(this->androids()->getSize()) * this->androids()->getDamaged();
	unsigned long long andGot        = min(andReq, this->androidsAssignment.assignedDroids);
	                   andPts        = (unsigned long long)andGot * (unsigned long long)androidsPower;
};

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

void mechanicsClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long andPts        = 0;
	this->androidsDistribution(andPts, androidsPower);
	this->androids()->repair(andPts * seconds);
};

unsigned long long mechanicsClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long andPts        = 0;
	this->androidsDistribution(andPts, androidsPower);
	if (0 < andPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->androids()->pointsToCheckpoint(), andPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

void warehouseClass::addCachedSeparateItem(separateItemClass * separateItem)
{
	if ((!separateItem) || (separateItem->isNull()))
	{
		return;
	}

	this->storageIDs_.push_back(separateItem->getID());
};

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

void warehouseClass::addUncachedSeparateItemAndCacheIt(separateItemClass * separateItem)
{
	if ((!separateItem) || (separateItem->isNull()))
	{
		return;
	}

	this->storageIDs_.push_back(actx->cacheItemsList.insertItem(separateItem));
};

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

void warehouseClass::addStackableItem(stackableItemClass * stackableItem, unsigned long long working, unsigned long long damaged, bool removePatternIfEmpty)
{
	if ((!stackableItem) || (stackableItem->isNull()))
	{
		return;
	}

	bool done = 0;

	if (PATTERN_ID_MAGNETICAL_GRID == stackableItem->getPatternID())
	{
		if (this->nullMagneticalGrid())
		{
			this->setMagneticalGridID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
		}
		this->magneticalGrid()->addWorking(working);
		this->magneticalGrid()->addDamaged(damaged);
		done = 1;
	}
	if (PATTERN_ID_TRANSPORT_CONTAINER == stackableItem->getPatternID())
	{
		if (this->nullTransportContainer())
		{
			this->setTransportContainerID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
		}
		this->transportContainer()->addWorking(working);
		this->transportContainer()->addDamaged(damaged);
		done = 1;
	}
	if (PATTERN_ID_ENERGETIC_CELL == stackableItem->getPatternID())
	{
		if (this->nullEnergeticCell())
		{
			this->setEnergeticCellID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
		}
		this->energeticCell()->addWorking(working);
		this->energeticCell()->addDamaged(damaged);
		done = 1;
	}

	if (!(done))
	{
		for (dtIdentifierList::iterator litp1 = this->storageIDs_.begin(); this->storageIDs_.end() != litp1; litp1++)
		{
			commonItemClass * storageItem = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
			if ((NOT_VALID_ID                != stackableItem->getPatternID()) &&
				(storageItem->getPatternID() == stackableItem->getPatternID()))
			{
				((stackableItemClass *)(storageItem))->addWorking(working);
				((stackableItemClass *)(storageItem))->addDamaged(damaged);
				done = 1;
				break;
			
			}
		}
	}

	if (!(done))
	{
		stackableItemClass * newStorageItem = stackableItem->createEmptyCopyOfItemOfTheSameClass();
		this->storageIDs_.push_back(actx->cacheItemsList.insertItem(newStorageItem));
		newStorageItem->addWorking(working);
		newStorageItem->addDamaged(damaged);
	}

	if (removePatternIfEmpty)
	{
		if (NOT_VALID_ID == stackableItem->getID())
		{
			delete stackableItem;
		}
		else
		{
			actx->cacheItemsList.deleteItem(stackableItem->getID());
		}
	}
};

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

void warehouseClass::subBundleFromItemsAndLeftItCached(tradeBundleClass * bundle)
{
	unsigned long long working;
	unsigned long long damaged;

	if (bundle->getItemsRecord(this->magneticalGridID_, working, damaged))
	{
		this->magneticalGrid()->subWorking(working);
		this->magneticalGrid()->subDamaged(damaged);
	}
	if (bundle->getItemsRecord(this->transportContainerID_, working, damaged))
	{
		this->transportContainer()->subWorking(working);
		this->transportContainer()->subDamaged(damaged);
	}
	if (bundle->getItemsRecord(this->energeticCellID_, working, damaged))
	{
		this->energeticCell()->subWorking(working);
		this->energeticCell()->subDamaged(damaged);
	}

	dtIdentifierList::iterator litp1 = this->storageIDs_.begin();
	while (this->storageIDs_.end() != litp1)
	{
		if (bundle->getItemsRecord((*litp1), working, damaged))
		{
			commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
			bool isItemEmpty = 0;
			if (item->isStackable())
			{
				stackableItemClass * stackableItem = (stackableItemClass *)item;
				stackableItem->subWorking(working);
				stackableItem->subDamaged(damaged);
				isItemEmpty = (!(0 < stackableItem->getCount()));
			}
			else
			{
				isItemEmpty = 1;
			}
			if (isItemEmpty)
			{
				litp1 = this->storageIDs_.erase(litp1);
			}
			else
			{
				litp1++;
			}
		}
		else
		{
			litp1++;
		}
	}
};

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

void warehouseClass::mergeItemsWithBundle(tradeBundleClass * bundle)
{
	typedef map<dtIdentifier, dtIdentifierList::iterator> patternsMap;
	patternsMap warehouseMap;
	warehouseMap.clear();

	for (dtIdentifierList::iterator litp1 = this->storageIDs_.begin(); this->storageIDs_.end() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
		if (item->isStackable())
		{
			warehouseMap.insert(make_pair(item->getPatternID(), litp1));
		}
	}

	for (tradeMap::iterator litp1 = bundle->bundleBegin(); bundle->bundleEnd() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(litp1->first);
		if (item->isStackable())
		{
			stackableItemClass * stackableItem = (stackableItemClass *)item;
			bool done = 0;
			if (PATTERN_ID_MAGNETICAL_GRID == item->getPatternID())
			{
				if (this->nullMagneticalGrid())
				{
					this->setMagneticalGridID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
				}
				this->magneticalGrid()->addWorking(litp1->second.workingCount);
				this->magneticalGrid()->addDamaged(litp1->second.damagedCount);
				done = 1;
			}
			if (PATTERN_ID_TRANSPORT_CONTAINER == item->getPatternID())
			{
				if (this->nullTransportContainer())
				{
					this->setTransportContainerID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
				}
				this->transportContainer()->addWorking(litp1->second.workingCount);
				this->transportContainer()->addDamaged(litp1->second.damagedCount);
				done = 1;
			}
			if (PATTERN_ID_ENERGETIC_CELL == item->getPatternID())
			{
				if (this->nullEnergeticCell())
				{
					this->setEnergeticCellID(actx->cacheItemsList.insertItem(stackableItem->createEmptyCopyOfItemOfTheSameClass()));
				}
				this->energeticCell()->addWorking(litp1->second.workingCount);
				this->energeticCell()->addDamaged(litp1->second.damagedCount);
				done = 1;
			}
			if (!(done))
			{
				stackableItemClass * newStackableItem;
				patternsMap::iterator patternsIterator = warehouseMap.find(item->getPatternID());				
				if (warehouseMap.end() == patternsIterator)
				{
					newStackableItem = stackableItem->createEmptyCopyOfItemOfTheSameClass();
					this->storageIDs_.push_back(actx->cacheItemsList.insertItem(newStackableItem));
				}
				else
				{
					dtIdentifierList::iterator warehouseIterator = patternsIterator->second;
					newStackableItem = actx->cacheItemsList.getItem<stackableItemClass>(*warehouseIterator);
				}
				newStackableItem->addWorking(litp1->second.workingCount);
				newStackableItem->addDamaged(litp1->second.damagedCount);
			}
		}
		else
		{
			this->storageIDs_.push_back(item->getID());
		}
	}
};

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

void warehouseClass::freeEmptyItemsInBundle(tradeBundleClass * bundle, bool doNotFreeSeparateItems)
{
	for (tradeMap::iterator litp1 = bundle->bundleBegin(); bundle->bundleEnd() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(litp1->first);
		if (item->isStackable())
		{
			stackableItemClass * stackableItem = (stackableItemClass *)item;
			if ((!(0 < stackableItem->getCount())                      ) &&
				(PATTERN_ID_MAGNETICAL_GRID     != item->getPatternID()) &&
				(PATTERN_ID_TRANSPORT_CONTAINER != item->getPatternID()) &&
				(PATTERN_ID_ENERGETIC_CELL      != item->getPatternID()))
			{
				actx->cacheItemsList.deleteItem(litp1->first);
			}
		}
		else
		{
			if (!doNotFreeSeparateItems)
			{
				actx->cacheItemsList.deleteItem(litp1->first);
			}
		}
	}
};

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

void warehouseClass::tradeSubingPhase(warehouseClass * firstWarehouse, tradeBundleClass * firstOffer, warehouseClass * secondWarehouse, tradeBundleClass * secondOffer)
{
	firstWarehouse->subBundleFromItemsAndLeftItCached(firstOffer);
	secondWarehouse->subBundleFromItemsAndLeftItCached(secondOffer);
};

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

void warehouseClass::tradeAddingPhase(warehouseClass * firstWarehouse, tradeBundleClass * firstOffer, warehouseClass * secondWarehouse, tradeBundleClass * secondOffer)
{
	firstWarehouse->mergeItemsWithBundle(secondOffer);
	secondWarehouse->mergeItemsWithBundle(firstOffer);
};

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

void warehouseClass::tradePurifyPhase(warehouseClass * firstWarehouse, tradeBundleClass * firstOffer, warehouseClass * secondWarehouse, tradeBundleClass * secondOffer)
{
	firstWarehouse->freeEmptyItemsInBundle(firstOffer, 1);
	secondWarehouse->freeEmptyItemsInBundle(secondOffer, 1);
};

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

magneticalGridClass * warehouseClass::magneticalGrid()
{
	if (magneticalGridClass * result = actx->cacheItemsList.getItem<magneticalGridClass>(magneticalGridID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullMagneticalGridClass>(PATTERN_ID_MAGNETICAL_GRID);
	}
};

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

transportContainerClass * warehouseClass::transportContainer()
{
	if (transportContainerClass * result = actx->cacheItemsList.getItem<transportContainerClass>(transportContainerID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullTransportContainerClass>(PATTERN_ID_TRANSPORT_CONTAINER);
	}
};

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

energeticCellClass * warehouseClass::energeticCell()
{
	if (energeticCellClass * result = actx->cacheItemsList.getItem<energeticCellClass>(energeticCellID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullEnergeticCellClass>(PATTERN_ID_ENERGETIC_CELL);
	}
};

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

void warehouseClass::annihilate()
{
	if (this->avalMagneticalGrid())
	{
		actx->cacheItemsList.deleteItem(this->magneticalGridID_);
		this->magneticalGridID_ = NOT_VALID_ID;
	}
	if (this->avalEnergeticCell())
	{
		actx->cacheItemsList.deleteItem(this->energeticCellID_);
		this->energeticCellID_ = NOT_VALID_ID;
	}
	if (this->avalTransportContainer())
	{
		actx->cacheItemsList.deleteItem(this->transportContainerID_);
		this->transportContainerID_ = NOT_VALID_ID;
	}
	for (dtIdentifierList::iterator litp1 = this->storageIDs_.begin(); this->storageIDs_.end() != litp1; litp1++)
	{
		actx->cacheItemsList.deleteItem(*litp1);
	}
	this->storageIDs_.clear();
};

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

void warehouseClass::addItem(commonItemClass * item, unsigned long long working, unsigned long long damaged, bool removePatternIfEmpty)
{
	if (!item)
	{
		errLogicalError("Adding NULL item.");
		return;
	}
	else
	{
		if (item->isNull())
		{
			errLogicalError("Adding nullItem (ID %u).", (unsigned long long)item->getID());
			return;
		}
	}
	if (item->isStackable())
	{
		this->addStackableItem((stackableItemClass *)(item), working, damaged, removePatternIfEmpty);
	}
	else
	{
		if ((1 != working) || (0 != damaged))
		{
			errLogicalError("Manipulating with separateItem (ID %u) with invalid counts.", (unsigned long long)item->getID());
		}
		if (NOT_VALID_ID == item->getID())
		{
			this->addUncachedSeparateItemAndCacheIt((separateItemClass *)(item));
		}
		else
		{
			this->addCachedSeparateItem((separateItemClass *)(item));
		}
	}
};

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

void warehouseClass::addItem(commonItemClass * item, bool removePatternIfEmpty)
{
	if (!item)
	{
		errLogicalError("Adding NULL item.");
		return;
	}
	if (item->isStackable())
	{
		errLogicalError("Manipulating with stackable item (ID %u) without counts.", (unsigned long long)item->getID());
	}
	else
	{
		this->addItem(item, 1, 0, removePatternIfEmpty);
	}
};

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

void warehouseClass::dropItem(dtIdentifierList::iterator itemIterator, unsigned long long working, unsigned long long damaged, bool removeItemIfEmpty)
{
	if (this->storageIDs_.end() == itemIterator)
	{
		return;
	}

	commonItemClass * storagedItem = actx->cacheItemsList.getItem<commonItemClass>(*itemIterator);
	if (storagedItem->isStackable())
	{
		stackableItemClass * stackableStoragedItem = (stackableItemClass *)(storagedItem);
		stackableStoragedItem->subWorking(working);
		stackableStoragedItem->subDamaged(damaged);
		if (!(0 < stackableStoragedItem->getCount()))
		{
			if (removeItemIfEmpty)
			{
				actx->cacheItemsList.deleteItem(*itemIterator);
			}
			this->storageIDs_.erase(itemIterator);
		}
	}
	else
	{
		if (removeItemIfEmpty)
		{
			actx->cacheItemsList.deleteItem(*itemIterator);
		}
		this->storageIDs_.erase(itemIterator);
	}
};

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

void warehouseClass::dropItem(dtIdentifierList::iterator itemIterator, bool removeItemIfEmpty)
{
	if (this->storageIDs_.end() == itemIterator)
	{
		return;
	}

	commonItemClass * storagedItem = actx->cacheItemsList.getItem<commonItemClass>(*itemIterator);
	if (storagedItem->isStackable())
	{
		stackableItemClass * stackableStoragedItem = (stackableItemClass *)(storagedItem);
		this->dropItem(itemIterator, stackableStoragedItem->getWorking(), stackableStoragedItem->getDamaged(), removeItemIfEmpty);
	}
	else
	{
		this->dropItem(itemIterator, 1, 0, removeItemIfEmpty);
	}
};

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

dtIdentifierList::iterator warehouseClass::getIteratorByID(dtIdentifier itemID)
{
	for (dtIdentifierList::iterator litp1 = this->storageIDs_.begin(); this->storageIDs_.end() != litp1; litp1++)
	{
		if (itemID == (*litp1))
		{
			return litp1;
		}
	}
	return this->storageIDs_.end();
};

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

unsigned long long warehouseClass::getWarehouseWeight()
{
	unsigned long long itemsWeight = 0;

	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storageIDs_.end(); litp1++)
	{
		itemsWeight += actx->cacheItemsList.getItem<commonItemClass>(*litp1)->getTotalUniversalWeight();
	}

	return (unsigned long long)itemsWeight                                            +
		   (unsigned long long)magneticalGrid()->getAllStackedItemsTotalWeight()      +
		   (unsigned long long)transportContainer()-> getAllStackedItemsTotalWeight() +
		   (unsigned long long)energeticCell()->getAllStackedItemsTotalWeight();
};

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

unsigned long long warehouseClass::getSizeOfItemsInWarehouse()
{
	unsigned long long itemsSize = 0;

	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storageIDs_.end(); litp1++)
	{
		itemsSize += actx->cacheItemsList.getItem<commonItemClass>(*litp1)->getTotalUniversalSize();
	}

	return (unsigned long long)itemsSize                                           +
		   (unsigned long long)magneticalGrid()->getAllStackedItemsTotalSize()     +
		   (unsigned long long)transportContainer()->getAllStackedItemsTotalSize() +
		   (unsigned long long)energeticCell()->getAllStackedItemsTotalSize();
};

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

void warehouseClass::tradeItemsWithoutAnyControl(warehouseClass * firstWarehouse, tradeBundleClass * firstOffer, warehouseClass * secondWarehouse, tradeBundleClass * secondOffer)
{
	warehouseClass::tradeSubingPhase(firstWarehouse, firstOffer, secondWarehouse, secondOffer);
	warehouseClass::tradeAddingPhase(firstWarehouse, firstOffer, secondWarehouse, secondOffer);
	warehouseClass::tradePurifyPhase(firstWarehouse, firstOffer, secondWarehouse, secondOffer);
};

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

void warehouseClass::transferBundleIntoShell(fortressClass * shell, tradeBundleClass * bundle)
{
	this->subBundleFromItemsAndLeftItCached(bundle);
	((baseClass *)(shell))->acceptBundleAsShell(bundle);
	this->freeEmptyItemsInBundle(bundle, 1);
};

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

unsigned long long warehouseClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	result += this->getMaxRepairingMechanicsBySize(this->magneticalGrid()->getSize())     * this->magneticalGrid()->getDamaged()    ;
	result += this->getMaxRepairingMechanicsBySize(this->transportContainer()->getSize()) * this->transportContainer()->getDamaged();
	result += this->getMaxRepairingMechanicsBySize(this->energeticCell()->getSize())      * this->energeticCell()->getDamaged()     ;
	for (dtIdentifierList::iterator litp1 = this->storageBegin(); litp1 != this->storageEnd(); litp1++)
	{
		commonItemClass * storagedItem = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
		if (storagedItem->isStackable())
		{
			result += this->getMaxRepairingMechanicsBySize(storagedItem->getSize()) * ((stackableItemClass *)(storagedItem))->getDamaged();
		}
		else
		{
			if (0 < ((separateItemClass *)(storagedItem))->getDamage())
			{
				result += this->getMaxRepairingMechanicsBySize(storagedItem->getSize());
			}
		}
	}
	return result;
};

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

void warehouseClass::androidsDistribution(unsigned long long &mgrPts, unsigned long long &tcnPts, unsigned long long &eclPts, vector<unsigned long long> &itmPts, unsigned long androidsPower)
{
	unsigned long long mgrReq         = 0;
	unsigned long long tcnReq         = 0;
	unsigned long long eclReq         = 0;
	unsignedLongLongVector itmReq;
	itmReq.resize(this->storageIDs_.size(), 0);
	mgrReq                           += this->getMaxRepairingMechanicsBySize(this->magneticalGrid()->getSize())     * this->magneticalGrid()->getDamaged();
	tcnReq                           += this->getMaxRepairingMechanicsBySize(this->transportContainer()->getSize()) * this->transportContainer()->getDamaged();
	eclReq                           += this->getMaxRepairingMechanicsBySize(this->energeticCell()->getSize())      * this->energeticCell()->getDamaged();
	unsigned long      loopG          = 0;
	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storageIDs_.end(); litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
		if ((( (item->isStackable())) && (0 < ((stackableItemClass *)(item))->getDamaged())) ||
			((!(item->isStackable())) && (0 < ((separateItemClass *)(item))->getDamage())))
		{
			itmReq[loopG] += this->getMaxRepairingMechanicsBySize(item->getSize()) * item->getCount();
		}
		loopG++;
	}
	unsigned long long mgrGot         = 0;
	unsigned long long tcnGot         = 0;
	unsigned long long eclGot         = 0;
	unsignedLongLongVector itmGot;
	itmGot.resize(this->storageIDs_.size(), 0);
	stacksAndLimits piles;
	piles.push_back(make_pair(&mgrGot, mgrReq));
	piles.push_back(make_pair(&tcnGot, tcnReq));
	piles.push_back(make_pair(&eclGot, eclReq));
	for (unsigned long loop1 = 0; loop1 < storageIDs_.size(); loop1++)
	{
		piles.push_back(make_pair(&(itmGot[loop1]), itmReq[loop1]));
	}
	divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	                       mgrPts    = (unsigned long long)mgrGot * (unsigned long long)androidsPower;
						   tcnPts    = (unsigned long long)tcnGot * (unsigned long long)androidsPower;
						   eclPts    = (unsigned long long)eclGot * (unsigned long long)androidsPower;
	                       itmPts;
	itmPts.resize(this->storageIDs_.size());
	for (unsigned long loop1 = 0; loop1 < storageIDs_.size(); loop1++)
	{
		itmPts[loop1] = (unsigned long long)itmGot[loop1] * (unsigned long long)androidsPower;
	}
};

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

void warehouseClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower  = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long      mgrPts    = 0;
	unsigned long long      tcnPts    = 0;
	unsigned long long      eclPts    = 0;
	unsignedLongLongVector itmPts;
	itmPts.resize(this->storageIDs_.size());
	this->androidsDistribution(mgrPts, tcnPts, eclPts, itmPts, androidsPower);
	this->magneticalGrid()->repair    (mgrPts * seconds);
	this->transportContainer()->repair(tcnPts * seconds);
	this->energeticCell()->repair     (eclPts * seconds);
	unsigned long           loop1     = 0;
	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storageIDs_.end(); litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
		item->repair(itmPts[loop1] * seconds);
		loop1++;
	}
};

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

unsigned long long warehouseClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long      mgrPts   = 0;
	unsigned long long      tcnPts   = 0;
	unsigned long long      eclPts   = 0;
	unsignedLongLongVector itmPts;
	itmPts.resize(this->storageIDs_.size());
	this->androidsDistribution(mgrPts, tcnPts, eclPts, itmPts, androidsPower);
	unsigned long long secondsToMgr  = maxSecondsToChange;
	unsigned long long secondsToTcn  = maxSecondsToChange;
	unsigned long long secondsToEcl  = maxSecondsToChange;
	if (0 < mgrPts)
	{
		secondsToMgr = ullUpRoundDiv(this->magneticalGrid()->pointsToCheckpoint(), mgrPts);
	}
	if (0 < tcnPts)
	{
		secondsToTcn = ullUpRoundDiv(this->transportContainer()->pointsToCheckpoint(), tcnPts);
	}
	if (0 < eclPts)
	{
		secondsToEcl = ullUpRoundDiv(this->energeticCell()->pointsToCheckpoint(), eclPts);
	}
	unsigned long long result = min(maxSecondsToChange, 
		                        min(secondsToMgr, 
								min(secondsToTcn,
								    secondsToEcl)));
	unsigned long           loop1     = 0;
	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storageIDs_.end(); litp1++)
	{
		if (0 < itmPts[loop1])
		{
			commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
			result = min(result, ullUpRoundDiv(item->pointsToCheckpoint(), itmPts[loop1]));
		}
		loop1++;
	}
	return result;
};

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

plasmaFilterClass * otherEquipmentClass::plasmaFilter()
{
	if (plasmaFilterClass * result = actx->cacheItemsList.getItem<plasmaFilterClass>(plasmaFilterID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullPlasmaFilterClass>(PATTERN_ID_PLASMA_FILTER);
	}
};

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

scientificLabClass * otherEquipmentClass::scientificLab()
{
	if (scientificLabClass * result = actx->cacheItemsList.getItem<scientificLabClass>(scientificLabID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullScientificLabClass>(PATTERN_ID_SCIENTIFIC_LAB);
	}
};

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

lifeSupportClass * otherEquipmentClass::lifeSupport()
{
	if (lifeSupportClass * result = actx->cacheItemsList.getItem<lifeSupportClass>(lifeSupportID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullLifeSupportClass>(PATTERN_ID_LIFE_SUPPORT);
	}
};

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

subspaceTransmitterClass * otherEquipmentClass::subspaceTransmitter()
{
	if (subspaceTransmitterClass * result = actx->cacheItemsList.getItem<subspaceTransmitterClass>(subspaceTransmitterID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullSubspaceTransmitterClass>(PATTERN_ID_SUBSPACE_TRANSMITTER);
	}
};

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

void otherEquipmentClass::annihilate()
{
	if (this->avalPlasmaFilter())
	{
		actx->cacheItemsList.deleteItem(this->plasmaFilterID_);
		this->plasmaFilterID_ = NOT_VALID_ID;
	}
	if (this->avalScientificLab())
	{
		actx->cacheItemsList.deleteItem(this->scientificLabID_);
		this->scientificLabID_ = NOT_VALID_ID;
	}
	if (this->avalLifeSupport())
	{
		actx->cacheItemsList.deleteItem(this->lifeSupportID_);
		this->lifeSupportID_ = NOT_VALID_ID;
	}
	if (this->avalSubspaceTransmitter())
	{
		actx->cacheItemsList.deleteItem(this->subspaceTransmitterID_);
		this->subspaceTransmitterID_ = NOT_VALID_ID;
	}
};

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

unsigned long long otherEquipmentClass::getOtherEquipmentWeight()
{
	return (unsigned long long)plasmaFilter()->getWeight()        + 		   
		   (unsigned long long)lifeSupport()->getWeight()         +
		   (unsigned long long)subspaceTransmitter()->getWeight();
};

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

unsigned long long otherEquipmentClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->plasmaFilter()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->plasmaFilter()->getSize());
	}
	if (0 < this->scientificLab()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->scientificLab()->getSize());
	}
	if (0 < this->lifeSupport()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->lifeSupport()->getSize());
	}
	if (0 < this->subspaceTransmitter()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->subspaceTransmitter()->getSize());
	}
	return result;
};

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

void otherEquipmentClass::androidsDistribution(unsigned long long &pflPts, unsigned long long &sclPts, unsigned long long &lspPts, unsigned long long &stmPts, unsigned long androidsPower)
{
	unsigned long long pflReq        = 0;
	unsigned long long sclReq        = 0;
	unsigned long long lspReq        = 0;
	unsigned long long stmReq        = 0;
	if (0 < this->plasmaFilter()->getDamage())
	{
		pflReq += this->getMaxRepairingMechanicsBySize(this->plasmaFilter()->getSize());
	}
	if (0 < this->scientificLab()->getDamage())
	{
		sclReq += this->getMaxRepairingMechanicsBySize(this->scientificLab()->getSize());
	}
	if (0 < this->lifeSupport()->getDamage())
	{
		lspReq += this->getMaxRepairingMechanicsBySize(this->lifeSupport()->getSize());
	}
	if (0 < this->subspaceTransmitter()->getDamage())
	{
		stmReq += this->getMaxRepairingMechanicsBySize(this->subspaceTransmitter()->getSize());
	}
	unsigned long long pflGot        = 0;
	unsigned long long sclGot        = 0;
	unsigned long long lspGot        = 0;
	unsigned long long stmGot        = 0;
	if (this->androidsAssignment.assignedDroids < pflReq + sclReq + lspReq + stmReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&pflGot, pflReq));
		piles.push_back(make_pair(&sclGot, sclReq));
		piles.push_back(make_pair(&lspGot, lspReq));
		piles.push_back(make_pair(&stmGot, stmReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		pflGot                       = pflReq;
		sclGot                       = sclReq;
		lspGot                       = lspReq;
		stmGot                       = stmReq;
	}
	                   pflPts        = (unsigned long long)pflGot * (unsigned long long)androidsPower;
					   sclPts        = (unsigned long long)sclGot * (unsigned long long)androidsPower;
					   lspPts        = (unsigned long long)lspGot * (unsigned long long)androidsPower;
					   stmPts        = (unsigned long long)stmGot * (unsigned long long)androidsPower;
};

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

void otherEquipmentClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long pflPts        = 0;
	unsigned long long sclPts        = 0;
	unsigned long long lspPts        = 0;
	unsigned long long stmPts        = 0;
	this->androidsDistribution(pflPts, sclPts, lspPts, stmPts, androidsPower);
	this->plasmaFilter()->repair       (pflPts * seconds);
	this->scientificLab()->repair      (sclPts * seconds);
	this->lifeSupport()->repair        (lspPts * seconds);
	this->subspaceTransmitter()->repair(stmPts * seconds);
};

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

unsigned long long otherEquipmentClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long pflPts        = 0;
	unsigned long long sclPts        = 0;
	unsigned long long lspPts        = 0;
	unsigned long long stmPts        = 0;
	this->androidsDistribution(pflPts, sclPts, lspPts, stmPts, androidsPower);
	unsigned long long secondsToPfl  = maxSecondsToChange;
	unsigned long long secondsToScl  = maxSecondsToChange;
	unsigned long long secondsToLsp  = maxSecondsToChange;
	unsigned long long secondsToStm  = maxSecondsToChange;
	if (0 < pflPts)
	{
		secondsToPfl = ullUpRoundDiv(this->plasmaFilter()->pointsToCheckpoint(), pflPts);
	}
	if (0 < sclPts)
	{
		secondsToScl = ullUpRoundDiv(this->scientificLab()->pointsToCheckpoint(), sclPts);
	}
	if (0 < lspPts)
	{
		secondsToLsp = ullUpRoundDiv(this->lifeSupport()->pointsToCheckpoint(), lspPts);
	}
	if (0 < stmPts)
	{
		secondsToStm = ullUpRoundDiv(this->subspaceTransmitter()->pointsToCheckpoint(), stmPts);
	}
	return min(maxSecondsToChange,
		   min(secondsToPfl,
		   min(secondsToScl,
		   min(secondsToLsp,
		       secondsToStm))));
};

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

mainframeClass * mainframeSystemClass::mainframe()
{
	if (mainframeClass * result = actx->cacheItemsList.getItem<mainframeClass>(mainframeID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullMainframeClass>(PATTERN_ID_MAINFRAME);
	}
};

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

void mainframeSystemClass::annihilate()
{
	if (this->avalMainframe())
	{
		actx->cacheItemsList.deleteItem(this->mainframeID_);
		this->mainframeID_ = NOT_VALID_ID;
	}
};

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

dtIdentifier mainframeSystemClass::changeMainframe(dtIdentifier newMainframeID)
{
	dtIdentifier oldMainframe = this->mainframeID_;
	this->mainframeID_        = newMainframeID;

	this->mainframeEnergyDivision.maxPowerDrain = this->mainframe()->maxPossibleConsumption();

	return oldMainframe;
}

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

unsigned long long mainframeSystemClass::getMainframeSystemWeight()
{
	return (unsigned long long)mainframe()->getWeight();
};

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

unsigned long long mainframeSystemClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	if (0 < this->mainframe()->getDamage())
	{
		result += this->getMaxRepairingMechanicsBySize(this->mainframe()->getSize());
	}
	return result;
};

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

void mainframeSystemClass::androidsDistribution(unsigned long long &mfrPts, unsigned long androidsPower)
{
	unsigned long long mfrReq        = 0;
	if (0 < this->mainframe()->getDamage())
	{
		mfrReq += this->getMaxRepairingMechanicsBySize(this->mainframe()->getSize());
	}
	unsigned long long mfrGot        = min(mfrReq, this->androidsAssignment.assignedDroids);
	                   mfrPts        = (unsigned long long)mfrGot * (unsigned long long)androidsPower;
};

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

void mainframeSystemClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mfrPts        = 0;
	this->androidsDistribution(mfrPts, androidsPower);
	this->mainframe()->repair(mfrPts * seconds);
};

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

unsigned long long mainframeSystemClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mfrPts        = 0;
	this->androidsDistribution(mfrPts, androidsPower);
	if (0 < mfrPts)
	{
		return min(maxSecondsToChange, ullUpRoundDiv(this->mainframe()->pointsToCheckpoint(), mfrPts));
	}
	else
	{
		return maxSecondsToChange;
	}
};

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

void hangarsPortClass::annihilate()
{
	for (dtIdentifierDeque::iterator litp1 = this->hangarsIDs_.begin(); this->hangarsIDs_.end() != litp1; litp1++)
	{
		hangarClass * hangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
		if ((hangar                                    ) &&
			(NOT_VALID_ID != hangar->getDockingShipID()))
		{
			fortressClass * dockingShip = actx->cacheFortressesList.getItem<fortressClass>(hangar->getDockingShipID());
			dockingShip->annihilate();
		}
		if (hangar)
		{
			hangar->cancelConstruction();
		}
	}
	for (dtIdentifierDeque::iterator litp1 = this->hangarsIDs_.begin(); this->hangarsIDs_.end() != litp1; litp1++)
	{
		// hanhary neni mozne mazat zaroven s anihilaci lodi, protoze anihilovana lod ty hangary v ramci anihilace prohledava a hleda, ve kterem je
		hangarClass * hangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
		if (hangar)
		{
			actx->cacheItemsList.deleteItem(hangar->getID());
		}
	}
	this->hangarsIDs_.clear();
};

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

unsigned long long hangarsPortClass::getHangarsPortWeight()
{
	unsigned long long hangarsWeight = 0;

	hangarClass * h;
	for (unsigned long loop1 = 0; NULL != (h = hangars(loop1)); loop1++)
	{
		hangarsWeight += h->getWeight();
	}

	return (unsigned long long)hangarsWeight;
};

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

unsigned long long hangarsPortClass::getHangarsPortSize()
{
	unsigned long long hangarsSize = 0;

	hangarClass * h;
	for (unsigned long loop1 = 0; NULL != (h = hangars(loop1)); loop1++)
	{
		hangarsSize += h->getSize();
	}

	return (unsigned long long)hangarsSize;
};

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

unsigned long long hangarsPortClass::totalConstructingAndroidsRequired()
{
	unsigned long long result = 0;
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		result += this->getMaxRepairingMechanicsBySize(this->hangars(loop1)->getCreationsSize()) * this->hangars(loop1)->getCreationsCount();
	}
	return result;
};

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

bool hangarsPortClass::isHangarMounted(dtIdentifier hangarID)
{
	return isItemInContainer(hangarsIDs_, hangarID);
};

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

unsigned long long hangarsPortClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	for (unsigned long loop1 = 0; loop1 < hangarsIDs_.size(); loop1++)
	{
		hangarClass * mountedHangar = this->hangars(loop1);
		if (0 < mountedHangar->getDamage())
		{
			result += this->getMaxRepairingMechanicsBySize(mountedHangar->getSize());
		}
	}
	return result;
};

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

void hangarsPortClass::androidsDistribution(vector<unsigned long long> &hngPts, unsigned long androidsPower)
{
	unsignedLongLongVector hngReq;
	hngReq.resize(this->hangarsIDs_.size(), 0);
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		if (0 < this->hangars(loop1)->getDamage())
		{
			hngReq[loop1] += this->getMaxRepairingMechanicsBySize(this->hangars(loop1)->getSize());
		}
	}
	unsignedLongLongVector hngGot;
	hngGot.resize(this->hangarsIDs_.size(), 0);
	stacksAndLimits piles;
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		piles.push_back(make_pair(&(hngGot[loop1]), hngReq[loop1]));
	}
	divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	                       hngPts;
	hngPts.resize(this->hangarsIDs_.size(), 0);
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		hngPts[loop1] = (unsigned long long)hngGot[loop1] * (unsigned long long)androidsPower;
	}
};

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

void hangarsPortClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsignedLongLongVector hngPts;
	hngPts.resize(this->hangarsIDs_.size(), 0);
	this->androidsDistribution(hngPts, androidsPower);
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		this->hangars(loop1)->repair(hngPts[loop1] * seconds);
	}
};

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

unsigned long long hangarsPortClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	typedef vector<unsigned long long> unsignedLongLongVector;
	typedef vector<unsigned long     > unsignedLongVector;

	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsignedLongLongVector hngPts;
	hngPts.resize(this->hangarsIDs_.size(), 0);
	this->androidsDistribution(hngPts, androidsPower);
	unsigned long long result = maxSecondsToChange;
	for (unsigned long loop1 = 0; loop1 < this->hangarsIDs_.size(); loop1++)
	{
		if (0 < hngPts[loop1])
		{
			result = min(result, ullUpRoundDiv(this->hangars(loop1)->pointsToCheckpoint(), hngPts[loop1]));
		}
	}
	return result;
};

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

magneticalFilterClass * factoriesClass::magneticalFilter()
{
	if (magneticalFilterClass * result = actx->cacheItemsList.getItem<magneticalFilterClass>(magneticalFilterID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullMagneticalFilterClass>(PATTERN_ID_MAGNETICAL_FILTER);
	}
};

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

deuteriumDecomposerClass * factoriesClass::deuteriumDecomposer()
{
	if (deuteriumDecomposerClass * result = actx->cacheItemsList.getItem<deuteriumDecomposerClass>(deuteriumDecomposerID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullDeuteriumDecomposerClass>(PATTERN_ID_DEUTERIUM_DECOMPOSER);
	}
};

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

zirconiumReactorClass * factoriesClass::zirconiumReactor()
{
	if (zirconiumReactorClass * result = actx->cacheItemsList.getItem<zirconiumReactorClass>(zirconiumReactorID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullZirconiumReactorClass>(PATTERN_ID_ZIRCONIUM_REACTOR);
	}
};

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

ilmeniteFurnaceClass * factoriesClass::ilmeniteFurnace()
{
	if (ilmeniteFurnaceClass * result = actx->cacheItemsList.getItem<ilmeniteFurnaceClass>(ilmeniteFurnaceID_))
	{
		return result;
	}
	else
	{
		return actx->cacheNullItemsList.getItem<nullIlmeniteFurnaceClass>(PATTERN_ID_ILMENITE_FURNACE);
	}
};

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

void factoriesClass::annihilate()
{
	if (this->avalMagneticalFilter())
	{
		actx->cacheItemsList.deleteItem(this->magneticalFilterID_);
		this->magneticalFilterID_ = NOT_VALID_ID;
	}
	if (this->avalDeuteriumDecomposer())
	{
		actx->cacheItemsList.deleteItem(this->deuteriumDecomposerID_);
		this->deuteriumDecomposerID_ = NOT_VALID_ID;
	}
	if (this->avalZirconiumReactor())
	{
		actx->cacheItemsList.deleteItem(this->zirconiumReactorID_);
		this->zirconiumReactorID_ = NOT_VALID_ID;
	}
	if (this->avalIlmeniteFurnace())
	{
		actx->cacheItemsList.deleteItem(this->ilmeniteFurnaceID_);
		this->ilmeniteFurnaceID_ = NOT_VALID_ID;
	}
};

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

unsigned long long factoriesClass::getFactoriesWeight()
{
	return (unsigned long long)magneticalFilter()->getAllStackedItemsTotalWeight()    +
		   (unsigned long long)deuteriumDecomposer()->getAllStackedItemsTotalWeight() +
		   (unsigned long long)zirconiumReactor()->getAllStackedItemsTotalWeight()    +
		   (unsigned long long)ilmeniteFurnace()->getAllStackedItemsTotalWeight();
};

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

unsigned long long factoriesClass::getFactoriesSize()
{
	return (unsigned long long)magneticalFilter()->getAllStackedItemsTotalSize()    +
		   (unsigned long long)deuteriumDecomposer()->getAllStackedItemsTotalSize() +
		   (unsigned long long)zirconiumReactor()->getAllStackedItemsTotalSize()    +
		   (unsigned long long)ilmeniteFurnace()->getAllStackedItemsTotalSize();
};

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

unsigned long long factoriesClass::repairingAndroidsRequired()
{
	unsigned long long result = 0;
	result += this->getMaxRepairingMechanicsBySize(this->magneticalFilter()->getSize())    * this->magneticalFilter()->getDamaged()   ;
	result += this->getMaxRepairingMechanicsBySize(this->deuteriumDecomposer()->getSize()) * this->deuteriumDecomposer()->getDamaged();
	result += this->getMaxRepairingMechanicsBySize(this->zirconiumReactor()->getSize())    * this->zirconiumReactor()->getDamaged()   ;
	result += this->getMaxRepairingMechanicsBySize(this->ilmeniteFurnace()->getSize())     * this->ilmeniteFurnace()->getDamaged()    ;
	return result;
};

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

void factoriesClass::androidsDistribution(unsigned long long &mgfPts, unsigned long long &dedPts, unsigned long long &zirPts, unsigned long long &ilfPts, unsigned long androidsPower)
{
	unsigned long long mgfReq        = 0;
	unsigned long long dedReq        = 0;
	unsigned long long zirReq        = 0;
	unsigned long long ilfReq        = 0;
	mgfReq += this->getMaxRepairingMechanicsBySize(this->magneticalFilter()->getSize())    * this->magneticalFilter()->getDamaged()   ;
	dedReq += this->getMaxRepairingMechanicsBySize(this->deuteriumDecomposer()->getSize()) * this->deuteriumDecomposer()->getDamaged();
	zirReq += this->getMaxRepairingMechanicsBySize(this->zirconiumReactor()->getSize())    * this->zirconiumReactor()->getDamaged()   ;
	ilfReq += this->getMaxRepairingMechanicsBySize(this->ilmeniteFurnace()->getSize())     * this->ilmeniteFurnace()->getDamaged()    ;
	unsigned long long mgfGot        = 0;
	unsigned long long dedGot        = 0;
	unsigned long long zirGot        = 0;
	unsigned long long ilfGot        = 0;
	if (this->androidsAssignment.assignedDroids < mgfReq + dedReq + zirReq + ilfReq)
	{
		stacksAndLimits piles;
		piles.push_back(make_pair(&mgfGot, mgfReq));
		piles.push_back(make_pair(&dedGot, dedReq));
		piles.push_back(make_pair(&zirGot, zirReq));
		piles.push_back(make_pair(&ilfGot, ilfReq));
		divideIntoPiles(this->androidsAssignment.assignedDroids, piles);
	}
	else
	{
		mgfGot                       = mgfReq;
		dedGot                       = dedReq;
		zirGot                       = zirReq;
		ilfGot                       = ilfReq;
	}
	                   mgfPts        = (unsigned long long)mgfGot * (unsigned long long)androidsPower;
					   dedPts        = (unsigned long long)dedGot * (unsigned long long)androidsPower;
					   zirPts        = (unsigned long long)zirGot * (unsigned long long)androidsPower;
					   ilfPts        = (unsigned long long)ilfGot * (unsigned long long)androidsPower;
};

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

void factoriesClass::repair(fortressClass * owningFortress, unsigned long long seconds)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mgfPts        = 0;
	unsigned long long dedPts        = 0;
	unsigned long long zirPts        = 0;
	unsigned long long ilfPts        = 0;
	this->androidsDistribution(mgfPts, dedPts, zirPts, ilfPts, androidsPower);
	this->magneticalFilter()->repair   (mgfPts * seconds);
	this->deuteriumDecomposer()->repair(dedPts * seconds);
	this->zirconiumReactor()->repair   (zirPts * seconds);
	this->ilmeniteFurnace()->repair    (ilfPts * seconds);
};

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

unsigned long long factoriesClass::secondsToChange(fortressClass * owningFortress, unsigned long long maxSecondsToChange)
{
	unsigned long      androidsPower = owningFortress->mechanics.androids()->actualPointsPerSecond(owningFortress);
	unsigned long long mgfPts        = 0;
	unsigned long long dedPts        = 0;
	unsigned long long zirPts        = 0;
	unsigned long long ilfPts        = 0;
	this->androidsDistribution(mgfPts, dedPts, zirPts, ilfPts, androidsPower);
	unsigned long long secondsToMgf  = maxSecondsToChange;
	unsigned long long secondsToDed  = maxSecondsToChange;
	unsigned long long secondsToZir  = maxSecondsToChange;
	unsigned long long secondsToIlf  = maxSecondsToChange;
	if (0 < mgfPts)
	{
		secondsToMgf = ullUpRoundDiv(this->magneticalFilter()->pointsToCheckpoint(), mgfPts);
	}
	if (0 < dedPts)
	{
		secondsToDed = ullUpRoundDiv(this->deuteriumDecomposer()->pointsToCheckpoint(), dedPts);
	}
	if (0 < zirPts)
	{
		secondsToZir = ullUpRoundDiv(this->zirconiumReactor()->pointsToCheckpoint(), zirPts);
	}
	if (0 < ilfPts)
	{
		secondsToIlf = ullUpRoundDiv(this->ilmeniteFurnace()->pointsToCheckpoint(), ilfPts);
	}
	return min(maxSecondsToChange,
		   min(secondsToMgf,
		   min(secondsToDed,
		   min(secondsToZir,
		       secondsToIlf))));
};

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

/*
template<class itemClass>
itemClass * warehouseClass::getNthItemOfType(unsigned long position)
{
	for (dtIdentifierList::iterator litp1 = storageIDs_.begin(); litp1 != storeIDs_.end(); litp1++)
	{
		if (typeid(itemClass) == typeid(*(((actx->cacheItemsList))[*litp])))
		{
			if (0 < position)
			{
				position--;
			}
			else
			{
				return (itemClass*)(((actx->cacheItemsList))[*litp]);
			}
		}
	}
	return NULL;
};
*/

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

attackReportClass::~attackReportClass()
{
	if (this->suppressClientUpdate_)
	{
		return;
	}
	if (this->source_)
	{
		this->source_->sendAttackReport(this);
	}
	if (this->target_)
	{
		this->target_->sendAttackReport(this);
	};
}

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

void attackReportClass::readInitialValues(fortressClass * target)
{
	this->deflectorShieldsEnergyLoss = target->deflectorShields.deflectorShieldsEnergyState.energy;
	this->structuralIntegrityLoss    = target->actualStructuralIntegrity();
}

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

void attackReportClass::unreadFinalValues(fortressClass * target)
{
	this->deflectorShieldsEnergyLoss = ullSafeSub(this->deflectorShieldsEnergyLoss, target->deflectorShields.deflectorShieldsEnergyState.energy);
	this->structuralIntegrityLoss    = ullSafeSub(this->structuralIntegrityLoss, target->actualStructuralIntegrity());

	double deflectorsMaxEnergy    = (double)target->deflectorShields.deflectorShieldsGenerator()->clientAccumulator();
	double structuralMaxIntegrity = (double)target->totalStructuralIntegrity();
	if (0 < deflectorsMaxEnergy)
	{
		this->deflectorShieldsEnergyLossPerc = (double)HUNDRED_PERCENT * (double)this->deflectorShieldsEnergyLoss / (double)deflectorsMaxEnergy;
	}
	else
	{
		this->deflectorShieldsEnergyLossPerc = 0;
	}
	if (0 < structuralMaxIntegrity)
	{
		this->structuralIntegrityLossPerc = (double)HUNDRED_PERCENT * (double)this->structuralIntegrityLoss / (double)structuralMaxIntegrity;
	}
	else
	{
		this->structuralIntegrityLossPerc = 0;
	}
}

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

bool attackReportClass::offensiveReport(fortressClass * reader)
{
	if ((reader) && (this->source_))
	{
		return reader->getID() == this->source_->getID();
	}
	else
	{
		return 0;
	}
}

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

bool attackReportClass::defensiveReport(fortressClass * reader)
{
	if ((reader) && (this->target_))
	{
		return reader->getID() == this->target_->getID();
	}
	else
	{
		return 0;
	}
}

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

void fortressClass::switchOffMainframeDueToEnergyLack()
{
	this->getFortressRealm()->mainframeFailure(this);
}

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

void fortressClass::lifeSupportNarrowDueToEnergyLack(double narrowCharging)
{
	unsigned long lifes = this->otherEquipment.lifeSupport()->lifesByConsumption(narrowCharging);
	unsigned long crewC = this->crew.getTotalCrewCount();
	lifes = min(lifes, crewC);
	this->crew.reasonableSacrifice(crewC - lifes);
}

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

void fortressClass::initRepairableSectionsVector(fortressSectionPVector & sectionVector)
{
	sectionVector.push_back(&(this->structuralIntegrityVoidSection));
	sectionVector.push_back(&(this->energeticSystem               ));
	sectionVector.push_back(&(this->deflectorShields              ));
	sectionVector.push_back(&(this->weapons                       ));
	sectionVector.push_back(&(this->transportBeam                 ));
	sectionVector.push_back(&(this->miningDevices                 ));
	sectionVector.push_back(&(this->probeDevices                  ));
	sectionVector.push_back(&(this->sensors                       ));
	sectionVector.push_back(&(this->cloaking                      ));
	sectionVector.push_back(&(this->mechanics                     ));
	sectionVector.push_back(&(this->warehouse                     ));
	sectionVector.push_back(&(this->otherEquipment                ));
	sectionVector.push_back(&(this->mainframeSystem               ));

	this->initRepairableSpecificSectionsVector(sectionVector);
};

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

bool fortressClass::getDistanceToTheWeaponsTarget(dist_t & distance)
{
	if (NOT_VALID_ID == this->targetOfWeapons_)
	{
		distance = 0;
		return 0;
	}
	return this->getDistanceFrom(actx->cacheFortressesList.getItem<fortressClass>(this->targetOfWeapons_), distance);
}

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

unsigned long long fortressClass::getLongestWeaponRange()
{
	unsigned long long result = 0;
	droneMissileLauncherClass * dml;
	if (0 < this->weapons.droneMissiles()->getWorking())
	{
		for (unsigned long loop1 = 0; NULL != (dml = this->weapons.droneMissileLaunchersOnly(loop1)); loop1++)
		{
			if (0 < dml->getStatus())
			{
				result = max(result, this->weapons.droneMissiles()->actualRange(this->realmID_));
				break;
			}
		}
	}
	laserGunClass * lg;
	for (unsigned long loop1 = 0; NULL != (lg = this->weapons.laserGunsOnly(loop1)); loop1++)
	{
		if (0 < lg->getStatus())
		{
			result = max(result, lg->actualRange());
		}
	}
	return result;
}

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

bool fortressClass::isProtectedFromAttacksAndScanning()
{
	if ((FT_SHIP == this->getFortressType()             ) &&
		(((shipClass *)(this))->MovementIsDockedInBase()))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

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

bool fortressClass::isTargetProtectedFromAttacks()
{
	if (NOT_VALID_ID == this->targetOfWeapons_)
	{
		return 0;
	}
	if ((FT_SHIP == actx->cacheFortressesList.getItem<fortressClass>(this->targetOfWeapons_)->getFortressType()) &&
		(actx->cacheFortressesList.getItem<shipClass>(this->targetOfWeapons_)->MovementIsDockedInBase()        ))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isAttackPrevented()
{
	return (this->isProtectedFromAttacksAndScanning()) || (this->isTargetProtectedFromAttacks());
};

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

bool fortressClass::isTargetHiddenForScanning(fortressClass * target)
{
	if (this->getFortressRealmID() == target->getFortressRealmID())
	{
		return 0;
	}
	unsigned long cloakingLevel  = target->cloaking.cloakingDevice()->actualLevel();
	unsigned long revealingLevel = this->sensors.highResolutionSensors()->actualLevel();
	if ((NOT_VALID_ID != target->targetOfWeapons_          ) ||
		(!(target->cloaking.cloakingPowerState.isWorking())))
	{
		cloakingLevel = 0;
	}
	if (!(this->sensors.sensorsHRPowerState.isWorking()))
	{
		revealingLevel = 0;
	}

	if (revealingLevel < cloakingLevel)
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isTargetHiddenForObserving(fortressClass * target)
{
	unsigned long cloakingLevel  = target->cloaking.cloakingDevice()->actualLevel();
	unsigned long revealingLevel = this->sensors.longRangeSensors()->actualLevel();
	if ((NOT_VALID_ID != target->targetOfWeapons_          ) ||
		(!(target->cloaking.cloakingPowerState.isWorking())))
	{
		cloakingLevel = 0;
	}
	if (!(this->sensors.sensorsLRPowerState.isWorking()))
	{
		revealingLevel = 0;
	}

	if (revealingLevel < cloakingLevel)
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isInRangeForConquer(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if ((this->isTargetInRangeRing3(target)) || (this->isTargetInRangeRing2(target)))
	{
		if ((FT_SHIP == this->getFortressType()             ) &&
			(((shipClass *)(this))->MovementIsDockedInBase()) &&
			(!(this->isTargetInRangeRing0(target))          ))
		{
			return 0;
		}
		if ((FT_SHIP == target->getFortressType()             ) &&
			(((shipClass *)(target))->MovementIsDockedInBase()) &&
			(!(this->isTargetInRangeRing0(target))            ))
		{
			return 0;
		}
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isInRangeForAttack(fortressClass * target)
{
	dist_t distanceFromTarget = 0;
	if ((target                                                         ) &&
		(this->getID() != target->getID()                               ) &&
		(this->getDistanceFrom(target, distanceFromTarget)              ) &&
		(ullUpRound(distanceFromTarget) <= this->getLongestWeaponRange()) &&
		(!(this->isProtectedFromAttacksAndScanning())                   ) &&
		(!(target->isProtectedFromAttacksAndScanning())                 ))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isInRangeForTrade(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing2(target))
	{
		if ((FT_SHIP == this->getFortressType()             ) &&
			(((shipClass *)(this))->MovementIsDockedInBase()) &&
			(!(this->isTargetInRangeRing0(target))          ))
		{
			return 0;
		}
		if ((FT_SHIP == target->getFortressType()             ) &&
			(((shipClass *)(target))->MovementIsDockedInBase()) &&
			(!(this->isTargetInRangeRing0(target))            ))
		{
			return 0;
		}
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isInRangeForScanning(fortressClass * target)
{
	dist_t distanceFromTarget = 0;
	if ((target                                                                                                    ) &&
		(this->sensors.sensorsHRPowerState.isWorking()                                                             ) &&
		(!(this->isTargetHiddenForScanning(target))                                                                ) &&
		(!(this->isProtectedFromAttacksAndScanning())                                                              ) &&
		(!(target->isProtectedFromAttacksAndScanning())                                                            ) &&
		(this->getDistanceFrom(target, distanceFromTarget)                                                         ) &&
		(ullUpRound(distanceFromTarget) <= (unsigned long long)this->sensors.highResolutionSensors()->actualRange()))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isInRangeForObserving(fortressClass * target)
{
	dist_t distanceFromTarget = 0;
	if ((target                                                                                               ) &&
		(this->sensors.sensorsLRPowerState.isWorking()                                                        ) &&
		(!(this->isTargetHiddenForObserving(target))                                                          ) &&
		(!(this->isProtectedFromAttacksAndScanning())                                                         ) &&
		(!(target->isProtectedFromAttacksAndScanning())                                                       ) &&
		(this->getDistanceFrom(target, distanceFromTarget)                                                    ) &&
		(ullUpRound(distanceFromTarget) <= (unsigned long long)this->sensors.longRangeSensors()->actualRange()))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

void fortressClass::getFortressesInFreeSpaceRange(dtIdentifierList & bases, dtIdentifierList & ships, unsigned long long range)
{
	vector_dist_t position;
	switch (this->getFortressType())
	{
	case FT_BASE:
		position = ((baseClass *)(this))->MovementGetBasePosition();
		break;
	case FT_SHIP:
		position = ((shipClass *)(this))->MovementGetShipPosition(1);
		break;
	default:
		errLogicalError("Unknown fortress type.");
		break;
	}
	this->getFortressesByPositionEx(position, (dist_t)range, ships, bases);
};

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

void fortressClass::getFortressesInRangeForConquer(dtIdentifierList * bases, dtIdentifierList * ships)
{
	if ((!bases) && (!ships))
	{
		return;
	}
	dtIdentifierList * workingBases;
	dtIdentifierList * workingShips;
	dtIdentifierList   basesVoidList;
	dtIdentifierList   shipsVoidList;
	if (!bases)
	{
		workingBases = &basesVoidList;
	}
	else
	{
		workingBases = bases;
	}
	if (!ships)
	{
		workingShips = &shipsVoidList;
	}
	else
	{
		workingShips = ships;
	}

	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		getShipsAndBasesInArea(thisBase->getFortressPlanet()->getID(), (*workingShips), (*workingBases), 1);
	}
	if (FT_SHIP == this->getFortressType())
	{
		shipClass   * thisShip = (shipClass *)this;
		spaceObject * center   = thisShip->getShipsAreaCenter();
		if (!center)
		{
			this->getFortressesInFreeSpaceRange((*workingBases), (*workingShips), (unsigned long long)RING4_RANGE_IN_KM);
		}
		else
		{
			switch (center->getType())
			{
			case SOT_BASE:
				workingBases->push_back(((spaceFortressObject *)(center))->getFortressID());
				break;
			case SOT_PLANET:
				getShipsAndBasesInArea(center->getID(), (*workingShips), (*workingBases), 1);
				break;
			case SOT_STAR:
				getShipsAndBasesInArea(center->getID(), (*workingShips), (*workingBases), 1);
				break;
			default:
				errLogicalError("Ship in unknown area (type %u).", (unsigned long long)center->getType());
				break;
			}
		}
	}

	dtIdentifierList::iterator litp1 = workingBases->begin();
	while (workingBases->end() != litp1)
	{
		if ((this->isInRangeForConquer (actx->cacheFortressesList.getItem<fortressClass>(*litp1))) &&
			(this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1))))
		{
			litp1++;
		}
		else
		{
			litp1 = workingBases->erase(litp1);
		}
	}
	litp1 = workingShips->begin();
	while (workingShips->end() != litp1)
	{
		if ((this->isInRangeForConquer (actx->cacheFortressesList.getItem<fortressClass>(*litp1))) &&
			(this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1))))
		{
			litp1++;
		}
		else
		{
			litp1 = workingShips->erase(litp1);
		}
	}
};

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

void fortressClass::getFortressesInRangeForAttack(dtIdentifierList * bases, dtIdentifierList * ships)
{
	if ((!bases) && (!ships))
	{
		return;
	}
	dtIdentifierList * workingBases;
	dtIdentifierList * workingShips;
	dtIdentifierList   basesVoidList;
	dtIdentifierList   shipsVoidList;
	if (!bases)
	{
		workingBases = &basesVoidList;
	}
	else
	{
		workingBases = bases;
	}
	if (!ships)
	{
		workingShips = &shipsVoidList;
	}
	else
	{
		workingShips = ships;
	}

	if (this->isProtectedFromAttacksAndScanning())
	{
		return;
	}

	vector_dist_t position;
	switch (this->getFortressType())
	{
	case FT_BASE:
		position = ((baseClass *)(this))->MovementGetBasePosition();
		break;
	case FT_SHIP:
		position = ((shipClass *)(this))->MovementGetShipPosition(1);
		break;
	default:
		errLogicalError("Unknown fortress type.");
		break;
	}
	
	this->getFortressesByPositionEx(position, (dist_t)this->getLongestWeaponRange(), (*workingShips), (*workingBases));

	dtIdentifierList::iterator litp1 = workingBases->begin();
	while (workingBases->end() != litp1)
	{
		fortressClass * actualFortress = actx->cacheFortressesList.getItem<fortressClass>(*litp1);
		if ((actualFortress                                        ) &&
			(!(actualFortress->isProtectedFromAttacksAndScanning())) &&
			(this->isInRangeForScanning(actualFortress)            ))
		{
			litp1++;
		}
		else
		{
			litp1 = workingBases->erase(litp1);
		}
	}
	litp1 = workingShips->begin();
	while (workingShips->end() != litp1)
	{
		fortressClass * actualFortress = actx->cacheFortressesList.getItem<fortressClass>(*litp1);
		if ((actualFortress                                        ) &&
			(!(actualFortress->isProtectedFromAttacksAndScanning())) &&
			(this->isInRangeForScanning(actualFortress)            ))
		{
			litp1++;
		}
		else
		{
			litp1 = workingShips->erase(litp1);
		}
	}
};

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

void fortressClass::getFortressesInRangeForTrade(dtIdentifierList * bases, dtIdentifierList * ships)
{
	if ((!bases) && (!ships))
	{
		return;
	}
	dtIdentifierList * workingBases;
	dtIdentifierList * workingShips;
	dtIdentifierList   basesVoidList;
	dtIdentifierList   shipsVoidList;
	if (!bases)
	{
		workingBases = &basesVoidList;
	}
	else
	{
		workingBases = bases;
	}
	if (!ships)
	{
		workingShips = &shipsVoidList;
	}
	else
	{
		workingShips = ships;
	}

	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		getShipsAndBasesInArea(thisBase->getFortressPlanet()->getID(), (*workingShips), (*workingBases), 1);
	}
	if (FT_SHIP == this->getFortressType())
	{
		shipClass   * thisShip = (shipClass *)this;
		spaceObject * center   = thisShip->getShipsAreaCenter();
		if (!center)
		{
			this->getFortressesInFreeSpaceRange((*workingBases), (*workingShips), (unsigned long long)RING2_RANGE_IN_KM);
		}
		else
		{
			switch (center->getType())
			{
			case SOT_BASE:
				workingBases->push_back(((spaceFortressObject *)(center))->getFortressID());
				break;
			case SOT_PLANET:
				getShipsAndBasesInArea(center->getID(), (*workingShips), (*workingBases), 1);
				break;
			case SOT_STAR:
				getShipsAndBasesInArea(center->getID(), (*workingShips), (*workingBases), 1);
				break;
			default:
				errLogicalError("Ship in unknown area (type %u).", (unsigned long long)center->getType());
				break;
			}
		}
	}

	dtIdentifierList::iterator litp1 = workingBases->begin();
	while (workingBases->end() != litp1)
	{
		if ((this->isInRangeForTrade   (actx->cacheFortressesList.getItem<fortressClass>(*litp1))) &&
			(this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1))))
		{
			litp1++;
		}
		else
		{
			litp1 = workingBases->erase(litp1);
		}
	}
	litp1 = workingShips->begin();
	while (workingShips->end() != litp1)
	{
		if ((this->isInRangeForTrade   (actx->cacheFortressesList.getItem<fortressClass>(*litp1))) &&
			(this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1))))
		{
			litp1++;
		}
		else
		{
			litp1 = workingShips->erase(litp1);
		}
	}
};

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

void fortressClass::getFortressesInRangeForScanning(dtIdentifierList * bases, dtIdentifierList * ships)
{
	if ((!bases) && (!ships))
	{
		return;
	}
	dtIdentifierList * workingBases;
	dtIdentifierList * workingShips;
	dtIdentifierList   basesVoidList;
	dtIdentifierList   shipsVoidList;
	if (!bases)
	{
		workingBases = &basesVoidList;
	}
	else
	{
		workingBases = bases;
	}
	if (!ships)
	{
		workingShips = &shipsVoidList;
	}
	else
	{
		workingShips = ships;
	}

	vector_dist_t position;
	switch (this->getFortressType())
	{
	case FT_BASE:
		position = ((baseClass *)(this))->MovementGetBasePosition();
		break;
	case FT_SHIP:
		position = ((shipClass *)(this))->MovementGetShipPosition(1);
		break;
	default:
		errLogicalError("Unknown fortress type.");
		break;
	}

	this->getFortressesByPositionEx(position, (dist_t)this->sensors.highResolutionSensors()->actualRange(), (*workingShips), (*workingBases));

	dtIdentifierList::iterator litp1 = workingBases->begin();
	while (workingBases->end() != litp1)
	{
		if (this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1)))
		{
			litp1++;
		}
		else
		{
			litp1 = workingBases->erase(litp1);
		}
	}
	litp1 = workingShips->begin();
	while (workingShips->end() != litp1)
	{
		if (this->isInRangeForScanning(actx->cacheFortressesList.getItem<fortressClass>(*litp1)))
		{
			litp1++;
		}
		else
		{
			litp1 = workingShips->erase(litp1);
		}
	}
};

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

void fortressClass::getFortressesInRangeForObserving(dtIdentifierList * bases, dtIdentifierList * ships)
{
	if ((!bases) && (!ships))
	{
		return;
	}
	dtIdentifierList * workingBases;
	dtIdentifierList * workingShips;
	dtIdentifierList   basesVoidList;
	dtIdentifierList   shipsVoidList;
	if (!bases)
	{
		workingBases = &basesVoidList;
	}
	else
	{
		workingBases = bases;
	}
	if (!ships)
	{
		workingShips = &shipsVoidList;
	}
	else
	{
		workingShips = ships;
	}

	vector_dist_t position;
	switch (this->getFortressType())
	{
	case FT_BASE:
		position = ((baseClass *)(this))->MovementGetBasePosition();
		break;
	case FT_SHIP:
		position = ((shipClass *)(this))->MovementGetShipPosition(1);
		break;
	default:
		errLogicalError("Unknown fortress type.");
		break;
	}
	this->getFortressesByPositionEx(position, (dist_t)this->sensors.longRangeSensors()->actualRange(), (*workingShips), (*workingBases));

	dtIdentifierList::iterator litp1 = workingBases->begin();
	while (workingBases->end() != litp1)
	{
		if (this->isInRangeForObserving(actx->cacheFortressesList.getItem<fortressClass>(*litp1)))
		{
			litp1++;
		}
		else
		{
			litp1 = workingBases->erase(litp1);
		}
	}
	litp1 = workingShips->begin();
	while (workingShips->end() != litp1)
	{
		if (this->isInRangeForObserving(actx->cacheFortressesList.getItem<fortressClass>(*litp1)))
		{
			litp1++;
		}
		else
		{
			litp1 = workingShips->erase(litp1);
		}
	}
};

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

conquerResultClass fortressClass::fallPrey()
{
	conquerResultClass result;

	if (this->isControllable())
	{
		result.addingResult_ = FAR_FORTRESS_ALREADY_OWNED;
		return result;
	}

	result.isMainframeAble_            = (this->mainframeSystem.avalMainframe()       ) && (!(this->mainframeSystem.mainframe()->isTotallyDevastated()           ));
	result.isEnergeticAccumulatorAble_ = (this->energeticSystem.energeticAccumulator()) && (!(this->energeticSystem.energeticAccumulator()->isTotallyDevastated()));
	
	for (dtIdentifierList::iterator litp1 = this->warehouse.storageBegin(); this->warehouse.storageEnd() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*litp1);
		if ((!(item->isStackable())) && (((separateItemClass *)item)->isTotallyDevastated()))
		{
			continue;
		}
		if ((item->isStackable()) && (0 == (((stackableItemClass *)item)->getWorking())))
		{
			continue;
		}
		if ((result.mainframeFailure()) && (PATTERN_ID_MAINFRAME == item->getPatternID()))
		{
			dtIdentifier oldMFID = this->mainframeSystem.changeMainframe(*litp1);
			if (NOT_VALID_ID == oldMFID)
			{
				this->warehouse.dropItem(litp1++, 0);
			}
			else
			{
				(*litp1) = oldMFID;
			}
			result.isMainframeAble_ = 1;
			continue;
		}
		if ((result.energeticAccumulatorFailure()) && (PATTERN_ID_ENERGETIC_ACCUMULATOR == item->getPatternID()))
		{
			dtIdentifier oldEA = this->energeticSystem.changeEnergeticAccumulator(*litp1);
			if (NOT_VALID_ID == oldEA)
			{
				this->warehouse.dropItem(litp1++, 0);
			}
			else
			{
				(*litp1) = oldEA;
			}
			result.isEnergeticAccumulatorAble_ = 1;
			continue;
		}
	}

	this->controllableTEMP_ = 1;
	this->globalUpdate();
	if ((result.mainframeFailure()) || (result.energeticAccumulatorFailure()))
	{
		result.isEnoughEnergy_ = 1;
	}
	else
	{
		result.isEnoughEnergy_ = this->controllableTEMP_;
	}
	result.energy_ = (unsigned long long)this->energy_;

	result.areDetailsAvailable_ = 1;

	if ((result.energeticAccumulatorFailure()) || (result.energyFailure()))
	{
		result.addingResult_ = FAR_MAINFRAME_ENERGY_LACK;
	}
	if (result.mainframeFailure())
	{
		result.addingResult_ = FAR_MAINFRAME_NOT_MOUNTED;
	}

	return result;
};

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

fortressAddingResult fortressClass::conquerTarget(fortressClass * target, conquerResultClass * conquerResult)
{
	fortressAddingResult result = FAR_NULL_FORTRESS;
	if (!target)
	{
		if (conquerResult)
		{
			conquerResult->addingResult_ = FAR_NULL_FORTRESS;
		}
		return FAR_NULL_FORTRESS;
	}
	if (!(this->isInRangeForConquer(target)))
	{
		if (conquerResult)
		{
			conquerResult->addingResult_ = FAR_OUT_OF_RANGE;
		}
		return FAR_OUT_OF_RANGE;
	}

	conquerResultClass resultParam = target->fallPrey();

	if (resultParam.isFallenPreyButNotAdded())
	{
		result = this->getFortressRealm()->addNewFortress(target);
		target->globalUpdate();
	}

	if (conquerResult)
	{
		(*conquerResult) = resultParam;
	}

	return result;
};

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

bool fortressClass::isFortressClassAvailable(dtIdentifier classID)
{
	fortressClassClass * actualClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(classID);
	if (!actualClass)
	{
		return 0;
	}

	if (FT_BASE == actualClass->getClassType())
	{
		double basesScience = this->getFortressRealm()->getScientificTree()->getRealScienceLevel(SCIENCE_ENTITY_BASES, INDEX_BASES_LEVEL);
		double basesQuality = basesScience / (double)MAX_TOTAL_SCIENCE_LEVEL;
		return basesQuality >= actualClass->getQualityRating();
	}
	if (FT_SHIP == actualClass->getClassType())
	{
		double shipsScience = this->getFortressRealm()->getScientificTree()->getRealScienceLevel(SCIENCE_ENTITY_SHIPS, INDEX_SHIPS_LEVEL);
		double shipsQuality = shipsScience / (double)MAX_TOTAL_SCIENCE_LEVEL;
		return shipsQuality >= actualClass->getQualityRating();
	}
	return 0;
};

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

void fortressClass::getAvailableFortressClasses(dtIdentifierList * fortressClasses, dtIdentifierList * basesClasses, dtIdentifierList * shipsClasses)
{
	if ((!fortressClasses) &&
		(!basesClasses   ) &&
		(!shipsClasses   ))
	{
		return;
	}

	dtIdentifierList * workingFortressClasses;
	dtIdentifierList * workingBasesClasses   ;
	dtIdentifierList * workingShipsClasses   ;
	dtIdentifierList   fc;
	dtIdentifierList   bc;
	dtIdentifierList   sc;

	if (!fortressClasses)
	{
		workingFortressClasses = &fc;
	}
	else
	{
		workingFortressClasses = fortressClasses;
	}
	if (!basesClasses)
	{
		workingBasesClasses = &bc;
	}
	else
	{
		workingBasesClasses = basesClasses;
	}
	if (!shipsClasses)
	{
		workingShipsClasses = &sc;
	}
	else
	{
		workingShipsClasses = shipsClasses;
	}

	for (dtIdentifier loop1 = 1; loop1 < actx->cacheFortressClassesList.getSize(); loop1++)
	{
		if (this->isFortressClassAvailable(loop1))
		{
			fortressClassClass * actualClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(loop1);
			workingFortressClasses->push_back(loop1);
			if (FT_BASE == actualClass->getClassType())
			{
				workingBasesClasses->push_back(loop1);
			}
			if (FT_SHIP == actualClass->getClassType())
			{
				workingShipsClasses->push_back(loop1);
			}
		}
	}
};

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

void fortressClass::getAvailableFortressClasses(dtIdentifierList * fortressClasses)
{
	this->getAvailableFortressClasses(fortressClasses, NULL, NULL);
};

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

void fortressClass::getAvailableFortressClasses(dtIdentifierList *basesClasses, dtIdentifierList *shipsClasses)
{
	this->getAvailableFortressClasses(NULL, basesClasses, shipsClasses);
};

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

unsigned long long fortressClass::requiredTitaniumToBuildAShell(spacePlanetObject * buildingPlanet)
{
	if (!(buildingPlanet))
	{
		return SHELL_MAX_BUILDING_TITANIUM;
	}
	double temperatureHostileModifier = buildingPlanet->getHostilityModifierByPlanetTemperature();
	double typeHostileModifier        = buildingPlanet->getHostilityModifierByPlanetType();
	double hostileModifier            = (double)1 - ((double)1 - temperatureHostileModifier) * ((double)1 - typeHostileModifier);
	hostileModifier                   = max((double)0, min((double)1, hostileModifier));
	return SHELL_MIN_BUILDING_TITANIUM + ullUpRound((double)(SHELL_MAX_BUILDING_TITANIUM - SHELL_MIN_BUILDING_TITANIUM) * (double)(hostileModifier));
};

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

unsigned long long fortressClass::missingTitaniumToBuildAShell(spacePlanetObject * buildingPlanet)
{
	unsigned long long requiredTitanium = this->requiredTitaniumToBuildAShell(buildingPlanet);
	return ullSafeSub(requiredTitanium, this->titaniumInKg(0));
};

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

baseBuildingResult fortressClass::buildNewBaseShell(dtIdentifier newFortressClassID, unsigned long long buildingTitanium)
{
	spacePlanetObject * buildingPlanet;
	if (!(this->isThereSomeAblePlanetToBuildAShell(&buildingPlanet)))
	{
		return BBR_NO_PLANET_IN_RANGE;
	}
	if (!(this->isEnoughResourcesToBuildAShell(buildingPlanet)))
	{
		return BBR_NOT_ENOUGH_TITANIUM;
	}

	unsigned long long requiredTitanium = this->requiredTitaniumToBuildAShell(buildingPlanet);
	this->subTitanium(requiredTitanium);

	fortressClassClass * newFortressClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(newFortressClassID);
	if ((!(newFortressClass)                                  ) || 
		(FT_BASE != newFortressClass->getClassType()          ) ||
		(!(this->isFortressClassAvailable(newFortressClassID))))
	{
		return BBR_INVALID_PARAMS;
	}
	fortressClass      * newBase          = newFortressClass->deriveNewFortress(NULL, buildingTitanium, 0);

	if (!newBase) 
	{
		return BBR_INVALID_PARAMS;
	}

	actx->cacheFortressesList.insertItem(newBase);
	newBase->addIDBehindName();

	if (0 == spaceFortressObject::createWithFortress(buildingPlanet->getID(), (baseClass *)newBase))
	{
		errLogicalError("Can't link base (ID %u) with planet (ID %u).", (unsigned long long)newBase->getID(), (unsigned long long)buildingPlanet->getID());
		return BBR_UNKNOWN_FAIL;
	};

	this->getFortressRealm()->addUncontrollableFortress(newBase);

	return BBR_SHELL_BUILT;
};

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

unsigned long long fortressClass::dockingDownCost()
{
	if (FT_SHIP != this->getFortressType())
	{
		return 0;
	}
	shipClass * thisShip = (shipClass *)this;
	if (!(0 < thisShip->impulsDrive.impulsJetEngine()->actualForceInGN()))
	{
		return 0;
	}

	unsigned long long totalRequiredForce = FORCE_BY_WEIGHT_LANDING_MULTIPLICATOR * thisShip->fortressTotalWeightWithPayload(0, 1);
	unsigned long long igniteSecond       = ullUpRoundDiv(totalRequiredForce, thisShip->impulsDrive.impulsJetEngine()->actualForceInGN() * GIGA);
	unsigned long long totalConsumption   = igniteSecond * thisShip->impulsDrive.impulsJetEngine()->actualConsumption();

	return totalConsumption;
};

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

dockingResult fortressClass::canDockDown(fortressClass * targetFortress, hangarClass ** dockingHangar)
{
	if (!targetFortress)
	{
		return DR_BAD_TARGET_FORTRESS_TYPE;
	}
	if (FT_SHIP != this->getFortressType())
	{
		return DR_BAD_SOURCE_FORTRESS_TYPE;
	}
	if (FT_BASE != targetFortress->getFortressType())
	{
		return DR_BAD_TARGET_FORTRESS_TYPE;
	}
	if (!(targetFortress->isControllable()))
	{
		return DR_UNCONTROLLABLE_TARGET;
	}
	if (this->getFortressRealmID() != targetFortress->getFortressRealmID())
	{
		return DR_NOT_YOUR_DOCK;
	}

	shipClass * source = (shipClass *)this;
	baseClass * target = (baseClass *)targetFortress;

	if ((!(source->getShipsAreaCenter())                                              ) || 
		(target->getFortressPlanet()->getID() != source->getShipsAreaCenter()->getID()))
	{
		return DR_OUT_OF_RANGE;
	}

	if ((source->impulsDrive.nullImpulsJetEngine()                     ) ||
		(source->impulsDrive.nullMechanicalDampers()                   ) ||
		(source->impulsDrive.impulsJetEngine()->isTotallyDevastated()  ) ||
		(source->impulsDrive.mechanicalDampers()->isTotallyDevastated()) ||
		(0 == source->impulsDrive.impulsJetEngine()->actualForceInGN() ))
	{
		return DR_IMPULS_DRIVE_FAIL;
	}

	if (this->deuteriumInKg(0) < this->dockingDownCost())
	{
		return DR_NOT_ENOUGH_DEUTERIUM;
	}

	hangarClass * freeHangar = NULL;
	for (dtIdentifierDeque::const_iterator litp1 = target->hangarsPort.beginHangarsIdentifiers(); target->hangarsPort.endHangarsIdentifiers() != litp1; litp1++)
	{
		if (actx->cacheItemsList.getItem<hangarClass>(*litp1)->isHangerFree())
		{
			freeHangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
			break;
		}
	}

	if (!freeHangar)
	{
		return DR_NO_FREE_HANGAR;
	}

	if (dockingHangar)
	{
		(*dockingHangar) = freeHangar;
	}

	return DR_OK;
};

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

dockingResult fortressClass::dockDown(fortressClass * targetFortress)
{
	hangarClass * dockingHangar;
	dockingResult result = this->canDockDown(targetFortress, &dockingHangar);
	if (DR_OK == result)
	{
		unsigned long long dockingDeuteriumCost = this->dockingDownCost();
		this->subDeuterium(dockingDeuteriumCost);
		if (!dockingHangar)
		{
			return DR_UNKNOWN_FAIL;
		}
		if ((FT_SHIP != this->getFortressType()) || (FT_BASE != targetFortress->getFortressType()))
		{
			return DR_UNKNOWN_FAIL;
		}
		if (!(dockingHangar->dockAShip(this)))
		{
			return DR_UNKNOWN_FAIL;
		}
		((shipClass *)(this))->MovementLand(targetFortress->getID());
	}
	return result;
};

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

unsigned long long fortressClass::unboundingCost()
{
	return TAKING_OFF_BY_LANDING_MULTIPLICATOR * this->dockingDownCost();
};

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

dockingResult fortressClass::canBeUnbounded()
{
	if (FT_SHIP != this->getFortressType())
	{
		return DR_BAD_SOURCE_FORTRESS_TYPE;
	}
	shipClass * thisShip = (shipClass *)this;
	if (!(thisShip->MovementIsDockedInBase()))
	{
		return DR_NOT_DOCKING_SHIP;
	}
	if ((thisShip->impulsDrive.nullImpulsJetEngine()                     ) ||
		(thisShip->impulsDrive.nullMechanicalDampers()                   ) ||
		(thisShip->impulsDrive.impulsJetEngine()->isTotallyDevastated()  ) ||
		(thisShip->impulsDrive.mechanicalDampers()->isTotallyDevastated()) ||
		(0 == thisShip->impulsDrive.impulsJetEngine()->actualForceInGN() ))
	{
		return DR_IMPULS_DRIVE_FAIL;
	}
	if (thisShip->deuteriumInKg(0) < this->unboundingCost())
	{
		return DR_NOT_ENOUGH_DEUTERIUM;
	}

	return DR_OK;
};

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

dockingResult fortressClass::unboundUp()
{
	dockingResult result = this->canBeUnbounded();
	if (DR_OK == result)
	{
		if (FT_SHIP != this->getFortressType())
		{
			return DR_UNKNOWN_FAIL;
		}
		shipClass * thisShip    = (shipClass *)this;
		baseClass * dockingBase = thisShip->getShipsDockingBase();
		if (!dockingBase)
		{
			return DR_UNKNOWN_FAIL;
		}
		for (dtIdentifierDeque::const_iterator litp1 = dockingBase->hangarsPort.beginHangarsIdentifiers(); dockingBase->hangarsPort.endHangarsIdentifiers() != litp1; litp1++)
		{
			hangarClass * hangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
			if (hangar->getDockingShipID() == thisShip->getID())
			{
				hangar->unboundAShip();
				break;
			}
		}
		thisShip->MovementTakeOff();
	}
	return result;
};

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

unsigned long long fortressClass::getFortressScientistsEffectivity()
{
	unsigned long long ablesScientists         = this->crew.getAblesCountOf(CREW_SCIENTIST);
	unsigned long long effectivesScientists    = min(ablesScientists, this->otherEquipment.scientificLab()->actualCapacity());
	unsigned long long scientificBonus         = this->otherEquipment.scientificLab()->actualLevel();
	unsigned long long scientificMultiplicator = 1 + scientificBonus;
	unsigned long long totalEffectivity        = effectivesScientists * scientificMultiplicator;
	return totalEffectivity;
};

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

dv_time::datetime fortressClass::quarkGluonPlasmaUpdate(dv_time::datetime updateToATime)
{
	this->quarkGluonPlasma_ = min(max(0, this->quarkGluonPlasma_), this->quarkGluonPlasmaLimitInMiligrams());

	double         increasePerGameSecond  = quarkGluonPlasmaQuarryingSpeed() - quarkGluonPlasmaConsumptionSpeed();

	if (0 == this->quarkGluonPlasmaUpdate_)
	{
		this->quarkGluonPlasmaUpdate_ = updateToATime - dv_time::encodeSeconds(1);
	}
	unsigned long long maxSecondsToChange = dv_time::secondsBegunBetween(this->quarkGluonPlasmaUpdate_, updateToATime, 1);
	unsigned long long resourceChange     = maxSecondsToChange;
	if (0 < increasePerGameSecond)
	{
		unsigned long long quarkGluonPlasmaSupplement = ullSafeSub(quarkGluonPlasmaLimitInMiligrams(), (unsigned long long)quarkGluonPlasma_);
		resourceChange = ullUpRound((double)quarkGluonPlasmaSupplement / increasePerGameSecond);
	}
	if (0 > increasePerGameSecond)
	{
		if (0 < quarkGluonPlasma_)
		{
			resourceChange = ullUpRound(quarkGluonPlasma_ / (-1 * increasePerGameSecond));
		}
		else
		{
			quarkGluonPlasma_ = 0;
			fallOutOfWarpDueToQuarkGluonPlasmaLack();
		}
	}

	unsigned long long secondsShift         = dv_time::secondsBegunBetween(quarkGluonPlasmaUpdate_, updateToATime, 1);
	unsigned long long secondsToChangeAfter = MAX_SECONDS_BETWEEN_QUARK_GLUON_PLASMA_UPDATES + secondsShift;
	if (secondsShift < maxSecondsToChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, maxSecondsToChange);
	}
	if (secondsShift < resourceChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, resourceChange);
	}

	double             increaseTotal   = increasePerGameSecond * (double)secondsShift;
	unsigned long long bottomLine      = 0;
	unsigned long long topLine         = quarkGluonPlasmaLimitInMiligrams();
	double             unlimitedResult = quarkGluonPlasma_ + increaseTotal;
	quarkGluonPlasma_                  = min(max(unlimitedResult, (double)bottomLine), (double)topLine);

	this->quarkGluonPlasma_ = min(max(0, this->quarkGluonPlasma_), this->quarkGluonPlasmaLimitInMiligrams());

	dv_time::datetime timeShift        = dv_time::encodeSeconds(secondsShift);
	dv_time::datetime changeAfter      = dv_time::encodeSeconds(secondsToChangeAfter) + this->quarkGluonPlasmaUpdate_;
	this->quarkGluonPlasmaUpdate_     += timeShift;

	if (this->quarkGluonPlasmaUpdate_ < updateToATime)
	{
		return this->quarkGluonPlasmaUpdate(updateToATime);
	}
	else
	{
		return changeAfter;
	}
};

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

void fortressClass::quarkGluonPlasmaUpdate()
{
	if (this->isShell(0))
	{
		return;
	}
	this->updateClient(0);
	dv_time::datetime actualGameTime = wt2gt(dv_time::now());
	dv_time::datetime nextUpdate     = quarkGluonPlasmaUpdate(actualGameTime);
	if ((nextUpdate < quarkGluonPlasmaTrigger_) || (quarkGluonPlasmaTrigger_ < actualGameTime + dv_time::encodeSeconds(1)))
	// novy trigger se nastavuje bud v pripade, ze je aktualnejsi nez doposud nastaveny,
	// nebo v pripade, ze nejaktualnejci trigger byl prave aktivovan (ta sekunda je tam pro jistotu)
	{
		gctx.eng.registerEvent(nextUpdate, new quarkGluonPlasmaUpdateTriggerClass(this->getID()), quarkGluonPlasmaTriggerIdentificator_);
		quarkGluonPlasmaTrigger_ = nextUpdate;
	}
};

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

void fortressClass::ulreaUpdate()
{
	if (this->isShell(0))
	{
		return;
	}

	this->updateClient(0);

	this->ulrea_ = max(0, this->ulrea_);

	double increasePerGameSecond = ulreaFilteringSpeed();

	if (0 == this->ulreaUpdate_)
	{
		this->ulreaUpdate_ = wt2gt(dv_time::now()) - dv_time::encodeSeconds(1);
	}
	if (0 == increasePerGameSecond)
	{
		ulreaUpdate_ = wt2gt(dv_time::now());
		return;
	}
	if (0 > increasePerGameSecond)
	{
        errLogicalError("fortress %u: decreasing ulrei", (unsigned long long)this->getID());
		return;
	}

	this->ulreaGradient_ = increasePerGameSecond;

	this->ulrea_ = max(0, this->ulrea_);

	dv_time::datetime  actualGameTime = wt2gt(dv_time::now());
	unsigned long long secondsShift   = dv_time::secondsBegunBetween(ulreaUpdate_, actualGameTime, 1);
	double             increaseTotal  = increasePerGameSecond * (double)secondsShift;

	ulrea_       += increaseTotal;
	ulreaUpdate_  = actualGameTime;
};

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

dv_time::datetime fortressClass::containeredResourcesUpdate(dv_time::datetime updateToATime)
{
	this->heavyWater_       = max(0, this->heavyWater_      );
	this->deuterium_        = max(0, this->deuterium_       );
	this->zirconiumCrystal_ = max(0, this->zirconiumCrystal_);
	this->ilmenite_         = max(0, this->ilmenite_        );
	this->titanium_         = max(0, this->titanium_        );
	double totalWeight      = this->heavyWater_                                   +
		                      this->deuterium_                                    +
							  this->zirconiumCrystal_                             +
							  this->ilmenite_                                     +
							  this->titanium_                                     ;
	double totalCapacity    = this->heavyWater_       / HEAVY_WATER_DENSITY       +
		                      this->deuterium_        / DEUTERIUM_DENSITY         +
							  this->zirconiumCrystal_ / ZIRCONIUM_CRYSTAL_DENSITY +
							  this->ilmenite_         / ILMENITE_DENSITY          +
							  this->titanium_         / TITANIUM_DENSITY          ;
	double freeResWeight    = (double)this->freeWeight(1, 1, 0);
	double freeResCapacity  = (double)this->commonRawMaterialCapacityLimit();
	if ((freeResWeight   < totalWeight  ) ||
		(freeResCapacity < totalCapacity))
	{
		double weightBalanceRatio    = (double)(freeResWeight  ) / (double)(totalWeight  );
		double capacityBalanceRatio  = (double)(freeResCapacity) / (double)(totalCapacity);
		double balanceRatio          = min(weightBalanceRatio, capacityBalanceRatio);
		this->heavyWater_           *= balanceRatio;
		this->deuterium_            *= balanceRatio;
		this->zirconiumCrystal_     *= balanceRatio;
		this->ilmenite_             *= balanceRatio;
		this->titanium_             *= balanceRatio;
	}

	// pri rekurzi budou increasy a decreasy nepresne, ale rekurze by stejne nemela vubec nastat, je to jen pro jistotu
	dv_time::datetime deuteriumFabricationChange = updateToATime + dv_time::encodeSeconds(MAX_SECONDS_BETWEEN_FABRICATING_CHANGES);
	dv_time::datetime titaniumFabricationChange  = updateToATime + dv_time::encodeSeconds(MAX_SECONDS_BETWEEN_FABRICATING_CHANGES);
	double            heavyWaterIncrease         = heavyWaterQuarryingSpeed();
	double            heavyWaterDecrease         = heavyWaterConsumptionSpeed();
	double            deuteriumIncrease          = deuteriumFabricationSpeed(&deuteriumFabricationChange);
	double            deuteriumDecrease          = deuteriumConsumptionSpeed();
	double            zirconiumCrystalIncrease   = zirconiumCrystalQuarryingSpeed();
	double            zirconiumCrystalDecrease   = zirconiumCrystalConsumptionSpeed();
	double            ilmeniteIncrease           = ilmeniteQuarryingSpeed();
	double            ilmeniteDecrease           = ilmeniteConsumptionSpeed();
	double            titaniumIncrease           = titaniumFabricationSpeed(&titaniumFabricationChange);
	double            titaniumDecrease           = 0;
	dv_time::datetime fabricationChange          = min(deuteriumFabricationChange, titaniumFabricationChange);

	double heavyWaterPerGameSecond        = heavyWaterIncrease       - heavyWaterDecrease      ;
	double deuteriumPerGameSecond         = deuteriumIncrease        - deuteriumDecrease       ;
	double zirconiumCrystalsPerGameSecond = zirconiumCrystalIncrease - zirconiumCrystalDecrease;
	double ilmenitePerGameSecond          = ilmeniteIncrease         - ilmeniteDecrease        ;
	double titaniumPerGameSecond          = titaniumIncrease         - titaniumDecrease        ;

	double weightIncreasePerGameSecound = heavyWaterPerGameSecond        +
		                                  deuteriumPerGameSecond         +
										  zirconiumCrystalsPerGameSecond +
										  ilmenitePerGameSecond          +
										  titaniumPerGameSecond;
	double sizeIncreasePerGameSecond    = heavyWaterPerGameSecond        / HEAVY_WATER_DENSITY       +
		                                  deuteriumPerGameSecond         / DEUTERIUM_DENSITY         +
										  zirconiumCrystalsPerGameSecond / ZIRCONIUM_CRYSTAL_DENSITY +
										  ilmenitePerGameSecond          / ILMENITE_DENSITY          +
										  titaniumPerGameSecond          / TITANIUM_DENSITY;

	unsigned long long freeWeightToLimit   = this->freeWeight(1, 0, 0);
	unsigned long long freeCapacityToLimit = this->freeTransportContainersCapacity(1, 0);

	if (0 == this->containeredResourcesUpdate_)
	{
		this->containeredResourcesUpdate_ = updateToATime - dv_time::encodeSeconds(1);
	}
	unsigned long long maxSecondsToChange               = dv_time::secondsBegunBetween(this->containeredResourcesUpdate_, updateToATime, 1);
	unsigned long long secondsToHeavyWaterChange        = maxSecondsToChange;
	unsigned long long secondsToDeuteriumChange         = maxSecondsToChange;
	unsigned long long secondsToZirconiumCrystalsChange = maxSecondsToChange;
	unsigned long long secondsToIlmeniteChange          = maxSecondsToChange;
	unsigned long long secondsToWeightLimit             = maxSecondsToChange;
	unsigned long long secondsToCapacityLimit           = maxSecondsToChange;
	unsigned long long secondsToFabricationChange       = dv_time::secondsBegunBetween(this->containeredResourcesUpdate_, fabricationChange, 1);
	secondsToFabricationChange = max(1, secondsToFabricationChange); // viz energyDistributionPhase
	if (0 > heavyWaterPerGameSecond)
	{
		if (0 < heavyWater_)
		{
			secondsToHeavyWaterChange = ullUpRound(heavyWater_ / (-1 * heavyWaterPerGameSecond));
		}
		else
		{
            errLogicalError("Fortress %u: heavy water is zero and still decreasing", (unsigned long long)this->getID());
			// toto by nemelo nastat, protoze spotrebu tezke vody sleduje jeji vlastni spotrebni funkce, stejne jako vyrobu deuteria, neni treba nic vypinat, jen se omezi fabrikace
		}
	}
	if (0 > deuteriumPerGameSecond)
	{
		if (0 < deuterium_)
		{
			secondsToDeuteriumChange = ullUpRound(deuterium_ / (-1 * deuteriumPerGameSecond));
		}
		else
		{
			switchOffImpulsDueToDeuteriumLack();
		}
	}
	if (0 > zirconiumCrystalsPerGameSecond)
	{
		if (0 < zirconiumCrystal_)
		{
			secondsToZirconiumCrystalsChange = ullUpRound(zirconiumCrystal_ / (-1 * zirconiumCrystalsPerGameSecond));
		}
		else
		{
            errLogicalError("Fortress %u: zirconium crystals are zero and still decreasing", (unsigned long long)this->getID());
			// spotreba zirkoniovych krystalu je regulovana pomoci spotrebni funkce a zavisla na vyrobe energie
		}
	}
	if (0 > ilmenitePerGameSecond)
	{
		if (0 < ilmenite_)
		{
			secondsToIlmeniteChange = ullUpRound(ilmenite_ / (-1 * ilmenitePerGameSecond));
		}
		else
		{
            errLogicalError("Fortress %u: ilmenite is zero and still decreasing", (unsigned long long)this->getID());
			// spotreba ilmenitu opet zavisi na vyrobe titanu a je regulovana spotrebnimi funkcemi
		}
	}
	if (0 > titaniumPerGameSecond)
	{
        errLogicalError("Fortress %u: titanium decreasing periodicaly", (unsigned long long)this->getID());
	}
	// tohle nakonec vyhazuji, protoze pretekani se nebude resit eventem, ale proste oriznutim pri kazdem updatu
	/*
	if (0 < weightIncreasePerGameSecound)
	{
		secondsToWeightLimit = ullUpRound((double)freeWeightToLimit / weightIncreasePerGameSecound);
	}
	if (0 < sizeIncreasePerGameSecond)
	{
		secondsToCapacityLimit = ullUpRound((double)freeCapacityToLimit / sizeIncreasePerGameSecond);
	}
	*/
	secondsToHeavyWaterChange        = max(1, secondsToHeavyWaterChange       );
	secondsToDeuteriumChange         = max(1, secondsToDeuteriumChange        );
	secondsToZirconiumCrystalsChange = max(1, secondsToZirconiumCrystalsChange);
	secondsToIlmeniteChange          = max(1, secondsToIlmeniteChange         );
	secondsToWeightLimit             = max(1, secondsToWeightLimit            );
	secondsToCapacityLimit           = max(1, secondsToCapacityLimit          );
	// viz. energyDistributionPhase
	unsigned long long secondsShift         = min(min(min(min(min(min(min(maxSecondsToChange, secondsToHeavyWaterChange), secondsToDeuteriumChange), secondsToZirconiumCrystalsChange), secondsToIlmeniteChange), secondsToWeightLimit), secondsToCapacityLimit), secondsToFabricationChange);
	unsigned long long secondsToChangeAfter = MAX_SECONDS_BETWEEN_CONTAINERED_RESOURCES_UPDATES + secondsShift;
	if (secondsShift < maxSecondsToChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, maxSecondsToChange);
	}
	if (secondsShift < secondsToHeavyWaterChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToHeavyWaterChange);
	}
	if (secondsShift < secondsToDeuteriumChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToDeuteriumChange);
	}
	if (secondsShift < secondsToZirconiumCrystalsChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToZirconiumCrystalsChange);
	}
	if (secondsShift < secondsToIlmeniteChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToIlmeniteChange);
	}
	if (secondsShift < secondsToWeightLimit)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToWeightLimit);
	}
	if (secondsShift < secondsToCapacityLimit)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToCapacityLimit);
	}
	if (secondsShift < secondsToFabricationChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToFabricationChange);
	}

	double hewDelta   = max((-1 * heavyWater_      ), secondsShift * heavyWaterPerGameSecond       );
	double deuDelta   = max((-1 * deuterium_       ), secondsShift * deuteriumPerGameSecond        );
	double zrcDelta   = max((-1 * zirconiumCrystal_), secondsShift * zirconiumCrystalsPerGameSecond);
	double ilmDelta   = max((-1 * ilmenite_        ), secondsShift * ilmenitePerGameSecond         );
	double titDelta   = max((-1 * titanium_        ), secondsShift * titaniumPerGameSecond         );
	double overWeight = hewDelta + deuDelta + zrcDelta + ilmDelta + titDelta - freeWeightToLimit;
	if (0 < overWeight)
	{
		if (overWeight < hewDelta)
		{
			hewDelta   -= overWeight;
			overWeight  = 0;
		}
		else
		{
			if (0 < hewDelta)
			{
				overWeight -= hewDelta;
				hewDelta    = 0;
			}
		}
		if (overWeight < ilmDelta)
		{
			ilmDelta   -= overWeight;
			overWeight  = 0;
		}
		else
		{
			if (0 < ilmDelta)
			{
				overWeight -= ilmDelta;
				ilmDelta    = 0;
			}
		}
		if (overWeight < zrcDelta)
		{
			zrcDelta   -= overWeight;
			overWeight  = 0;
		}
		else
		{
			if (0 < zrcDelta)
			{
				overWeight -= zrcDelta;
				zrcDelta    = 0;
			}
		}
		if (overWeight < deuDelta)
		{
			deuDelta   -= overWeight;
			overWeight  = 0;
		}
		else
		{
			if (0 < deuDelta)
			{
				overWeight -= deuDelta;
				deuDelta    = 0;
			}
		}
		if (overWeight < titDelta)
		{
			titDelta   -= overWeight;
			overWeight  = 0;
		}
		else
		{
			if (0 < titDelta)
			{
				overWeight -= titDelta;
				titDelta    = 0;
			}
		}
	}
	double overCapacity = hewDelta / HEAVY_WATER_DENSITY       +
		                  deuDelta / DEUTERIUM_DENSITY         +
						  zrcDelta / ZIRCONIUM_CRYSTAL_DENSITY +
						  ilmDelta / ILMENITE_DENSITY          +
						  titDelta / TITANIUM_DENSITY          -
						  freeCapacityToLimit;
	if (0 < overCapacity)
	{
		if (overCapacity * HEAVY_WATER_DENSITY < hewDelta)
		{
			hewDelta     -= overCapacity * HEAVY_WATER_DENSITY;
			overCapacity  = 0;
		}
		else
		{
			if (0 < hewDelta)
			{
				overCapacity -= hewDelta / HEAVY_WATER_DENSITY;
				hewDelta      = 0;
			}
		}
		if (overCapacity * ILMENITE_DENSITY < ilmDelta)
		{
			ilmDelta     -= overCapacity * ILMENITE_DENSITY;
			overCapacity  = 0;
		}
		else
		{
			if (0 < ilmDelta)
			{
				overCapacity -= ilmDelta / ILMENITE_DENSITY;
				ilmDelta      = 0;
			}
		}
		if (overCapacity * ZIRCONIUM_CRYSTAL_DENSITY < zrcDelta)
		{
			zrcDelta     -= overCapacity * ZIRCONIUM_CRYSTAL_DENSITY;
			overCapacity  = 0;
		}
		else
		{
			if (0 < zrcDelta)
			{
				overCapacity -= zrcDelta / ZIRCONIUM_CRYSTAL_DENSITY;
				zrcDelta      = 0;
			}
		}
		if (overCapacity * DEUTERIUM_DENSITY < deuDelta)
		{
			deuDelta     -= overCapacity * DEUTERIUM_DENSITY;
			overCapacity  = 0;
		}
		else
		{
			if (0 < deuDelta)
			{
				overCapacity -= deuDelta / DEUTERIUM_DENSITY;
				deuDelta      = 0;
			}
		}
		if (overCapacity * TITANIUM_DENSITY < titDelta)
		{
			titDelta     -= overCapacity * TITANIUM_DENSITY;
			overCapacity  = 0;
		}
		else
		{
			if (0 < titDelta)
			{
				overCapacity -= titDelta / TITANIUM_DENSITY;
				titDelta      = 0;
			}
		}
	}

	heavyWater_       += hewDelta;
	deuterium_        += deuDelta;
	zirconiumCrystal_ += zrcDelta;
	ilmenite_         += ilmDelta;
	titanium_         += titDelta;

	this->heavyWaterGradient_       = heavyWaterQuarryingSpeed()           - heavyWaterConsumptionSpeed()      ;
	this->deuteriumGradient_        = deuteriumFabricationSpeed(NULL)      - deuteriumConsumptionSpeed()       ;
	this->zirconiumCrystalGradient_ = zirconiumCrystalQuarryingSpeed()     - zirconiumCrystalConsumptionSpeed();
	this->ilmeniteGradient_         = ilmeniteQuarryingSpeed()             - ilmeniteConsumptionSpeed()        ;
	this->titaniumGradient_         = titaniumFabricationSpeed(NULL)                                           ;

	this->heavyWater_       = max(0, this->heavyWater_      );
	this->deuterium_        = max(0, this->deuterium_       );
	this->zirconiumCrystal_ = max(0, this->zirconiumCrystal_);
	this->ilmenite_         = max(0, this->ilmenite_        );
	this->titanium_         = max(0, this->titanium_        );
	totalWeight             = this->heavyWater_                                   +
		                      this->deuterium_                                    +
							  this->zirconiumCrystal_                             +
							  this->ilmenite_                                     +
							  this->titanium_                                     ;
	totalCapacity           = this->heavyWater_       / HEAVY_WATER_DENSITY       +
		                      this->deuterium_        / DEUTERIUM_DENSITY         +
							  this->zirconiumCrystal_ / ZIRCONIUM_CRYSTAL_DENSITY +
							  this->ilmenite_         / ILMENITE_DENSITY          +
							  this->titanium_         / TITANIUM_DENSITY          ;
	freeResWeight           = (double)this->freeWeight(1, 1, 0);
	freeResCapacity         = (double)this->commonRawMaterialCapacityLimit();
	if ((freeResWeight   < totalWeight  ) ||
		(freeResCapacity < totalCapacity))
	{
		double weightBalanceRatio    = (double)(freeResWeight  ) / (double)(totalWeight  );
		double capacityBalanceRatio  = (double)(freeResCapacity) / (double)(totalCapacity);
		double balanceRatio          = min(weightBalanceRatio, capacityBalanceRatio);
		this->heavyWater_           *= balanceRatio;
		this->deuterium_            *= balanceRatio;
		this->zirconiumCrystal_     *= balanceRatio;
		this->ilmenite_             *= balanceRatio;
		this->titanium_             *= balanceRatio;
	}

	dv_time::datetime timeShift        = dv_time::encodeSeconds(secondsShift);
	dv_time::datetime changeAfter      = dv_time::encodeSeconds(secondsToChangeAfter) + this->containeredResourcesUpdate_;
	this->containeredResourcesUpdate_ += timeShift;

	if (this->containeredResourcesUpdate_ < updateToATime)
	{
		return this->containeredResourcesUpdate(updateToATime);
	}
	else
	{
		return changeAfter;
	}
};

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

void fortressClass::containeredResourcesUpdate()
{
	if (this->isShell(0))
	{
		// skorapka je cela rizena energetickymi updaty
		this->energyDistributionPhaseAndWeaponsFire();
	}
	this->updateClient(0);
	dv_time::datetime actualGameTime = wt2gt(dv_time::now());
	dv_time::datetime nextUpdate     = containeredResourcesUpdate(actualGameTime);
	if ((nextUpdate < containeredResourcesTrigger_) || (containeredResourcesTrigger_ < actualGameTime + dv_time::encodeSeconds(1)))
	// novy trigger se nastavuje bud v pripade, ze je aktualnejsi nez doposud nastaveny,
	// nebo v pripade, ze nejaktualnejci trigger byl prave aktivovan (ta sekunda je tam pro jistotu)
	{
		gctx.eng.registerEvent(nextUpdate, new containeredResourcesUpdateTriggerClass(this->getID()), 
            containeredResourcesTriggerIdentificator_);
		containeredResourcesTrigger_ = nextUpdate;
	}
};

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

dv_time::datetime fortressClass::energyDistributionPhaseAndWeaponsFire(dv_time::datetime updateToATime)
// vrati vhodny cas pro dalsi update
{
	// menit targetEnergy pri poskozeni, protoze se meni kapacity
	// ne, to nejde, protoze pak nevime, jak se vracet zpatky - VYRESENO

	// poresit, kdyz neni z ceho dobit akumulator
	// toto se promita leckde, mimo jine i v tom, ze to muze vyvolet event, kdyz se akumulator nedobiji/nevybiji - ASI VYRESENO

	// predelat zbrane, nebo mozna jen kontrola - VYRESENO

	// overit, zda se to nemuse porad volat dokola kvuli zaokrouhlovani
	// co kdyz nekdo po mesici (900 hernich dnech) hodi energyDistribution

#ifdef DEBUG_URZA
	if ((DEBUG_URZA_FORTRESS == this->getID()) || (0 == DEBUG_URZA_FORTRESS))
	{
		//debugOut << "EDP.start: ID " << this->getID() << "; diff" << "; time " << updateToATime.toString() << "; from " << this->energyUpdate_.toString() << endl;
		debugOut << "..:: EP.START ::.." << endl << this->energyUpdate_.toString() << endl << updateToATime.toString() << endl;
	}
#endif

	if (this->isShell(1))
	{
		if (FT_BASE != this->getFortressType())
		{
			errLogicalError("Shell (ID %u) is not base!", (unsigned long long)this->getID());
			return updateToATime + dv_time::encodeSeconds(MAX_SECONDS_BETWEEN_ENERGETIC_PHASES);
		}
		baseClass * thisBase = (baseClass *)this;
		return thisBase->baseConstructingPhase(updateToATime);
	}

	this->updateClient(0);

	this->energy_ = min(max(this->energy_, 0), this->energyLimitInTeraJoules());
	unsigned long long energySupplies = (unsigned long long)energy_;
	// kdyz nemame energii sklade energii na dlouhy beh, zavolame update (ten ji muze vyrobit)
	if (energySupplies < (MAX_SECONDS_BETWEEN_ENERGETIC_PHASES * this->energeticSystem.energeticAccumulator()->actualCharging()))
	{
		containeredResourcesUpdate(updateToATime);
		energySupplies = (unsigned long long)energy_;
		// pokud je tato funkce zanorena (volana rekurzivne), mohlo zde byt hraci prilepseno, protoze mame k dispozici
		// energii, ktera se vyrobi az casem; tato situace by vsak nemela nastat a rekurze je tu jen jako bezpecnostni
		// mechanismus, teoreticky mel byt na kazdou zmenu aktivovan trigger a nemela byt resena zpetne (zpetne reseni
		// je jedina moznost, jak bychom mohli byt v rekurzi)
	}
	dv_time::datetime harvestingChange = updateToATime + dv_time::encodeSeconds(MAX_SECONDS_BETWEEN_FABRICATING_CHANGES);
	double harvestingSpeed = energyHarvestingSpeed(&harvestingChange);

	double deflectorsFullCharging  =         this->deflectorShields.deflectorShieldsGenerator()->actualCharging();
	double weaponsFullCharging     = (double)this->weapons.getTotalWeaponsCharging(this, NULL);
	double tBeamFullCharging       =         this->transportBeam.transportBeamGenerator()->actualCharging();
	double sensorsHRFullCharging   =         this->sensors.highResolutionSensors()->actualConsumption();
	double sensorsLRFullCharging   =         this->sensors.longRangeSensors()->actualConsumption();
	double cloakingFullCharging    =         this->cloaking.cloakingDevice()->actualConsumption();
	double androidsFullCharging    =         this->mechanics.androids()->actualConsumption(this->realmID_) * (double)this->mechanics.getMaxWorkingAndroids();
	double lifeSupportFullCharging =         this->otherEquipment.lifeSupport()->actualConsumption(this->crew.getTotalCrewCount());
	double mainframeFullCharging   =         this->mainframeSystem.mainframe()->actualConsumption();

	unsigned long long deflectorsRealTargetEnergy = min(this->deflectorShields.deflectorShieldsEnergyState.targetEnergy, this->deflectorShields.deflectorShieldsGenerator()->actualAccumulator());
	unsigned long long deflectorsEnergyDiff       = ullSafeSub(deflectorsRealTargetEnergy, this->deflectorShields.deflectorShieldsEnergyState.energy);

	unsigned long long weaponsEnergyDiffToTheFire = this->getTotalWeaponsEnergyDiffToTheFire();

	unsigned long long tBeamRealTargetEnergy      = min(this->transportBeam.tBeamEnergyState.targetEnergy, this->transportBeam.transportBeamGenerator()->actualAccumulator());
	unsigned long long tBeamEnergyDiff            = ullSafeSub(tBeamRealTargetEnergy, this->transportBeam.tBeamEnergyState.energy);
	// TODO az se zprovozni tBeam, tak ho tu poresit jako zbrane

	if (0 == deflectorsEnergyDiff)
	{
		if (0 < this->deflectorShields.deflectorShieldsEnergyState.targetEnergy)
		{
			deflectorsFullCharging = this->deflectorShields.deflectorShieldsGenerator()->actualLeak();
		}
		else
		{
			deflectorsFullCharging = 0;
		}
	}

	if (0 == weaponsEnergyDiffToTheFire)
	{
		weaponsFullCharging = 0;
	}

	if (0 == tBeamEnergyDiff)
	{
		tBeamFullCharging = 0;
	}

	if (PS_TURNED_OFF == this->sensors.sensorsHRPowerState.getState())
	{
		sensorsHRFullCharging = 0;
	}

	if (PS_TURNED_OFF == this->sensors.sensorsLRPowerState.getState())
	{
		sensorsLRFullCharging = 0;
	}

	if (PS_TURNED_OFF == this->cloaking.cloakingPowerState.getState())
	{
		cloakingFullCharging = 0;
	}

	if (PS_TURNED_OFF == this->mechanics.androidsPowerState.getState())
	{
		androidsFullCharging = 0;
	}

	double deflectorsLimitedCharging  = min((double)deflectorsFullCharging , (double)this->deflectorShields.deflectorsEnergyDivision.maxPowerDrain);
	double weaponsLimitedCharging     = min((double)weaponsFullCharging    , (double)this->weapons.weaponsEnergyDivision.maxPowerDrain            );
	double tBeamLimitedCharging       = min((double)tBeamFullCharging      , (double)this->transportBeam.tBeamEnergyDivision.maxPowerDrain        );
	double sensorsHRLimitedCharging   = min((double)sensorsHRFullCharging  , (double)this->sensors.sensorsHREnergyDivision.maxPowerDrain          );
	double sensorsLRLimitedCharging   = min((double)sensorsLRFullCharging  , (double)this->sensors.sensorsLREnergyDivision.maxPowerDrain          );
	double cloakingLimitedCharging    = min((double)cloakingFullCharging   , (double)this->cloaking.cloakingEnergyDivision.maxPowerDrain          );
	double androidsLimitedCharging    = min((double)androidsFullCharging   , (double)this->mechanics.androidsEnergyDivision.maxPowerDrain         );
	double lifeSupportLimitedCharging = min((double)lifeSupportFullCharging, (double)this->otherEquipment.lifeSupportEnergyDivision.maxPowerDrain );
	double mainframeLimitedCharging   = min((double)mainframeFullCharging  , (double)this->mainframeSystem.mainframeEnergyDivision.maxPowerDrain  );

	if ((this->deflectorShields.deflectorsEnergyDivision.shutDownOnEnergyLack) && (deflectorsLimitedCharging < deflectorsFullCharging))
	{
		deflectorsLimitedCharging = 0;
	}
	if ((this->weapons.weaponsEnergyDivision.shutDownOnEnergyLack) && (weaponsLimitedCharging < weaponsFullCharging))
	{
		weaponsLimitedCharging = 0;
	}
	if ((this->transportBeam.tBeamEnergyDivision.shutDownOnEnergyLack) && (tBeamLimitedCharging < tBeamFullCharging))
	{
		tBeamLimitedCharging = 0;
	}
	if ((this->sensors.sensorsHREnergyDivision.shutDownOnEnergyLack) && (sensorsHRLimitedCharging < sensorsHRFullCharging))
	{
		sensorsHRLimitedCharging = 0;
	}
	if ((this->sensors.sensorsLREnergyDivision.shutDownOnEnergyLack) && (sensorsLRLimitedCharging < sensorsLRFullCharging))
	{
		sensorsLRLimitedCharging = 0;
	}
	if ((this->cloaking.cloakingEnergyDivision.shutDownOnEnergyLack) && (cloakingLimitedCharging < cloakingFullCharging))
	{
		cloakingLimitedCharging = 0;
	}
	if ((this->mechanics.androidsEnergyDivision.shutDownOnEnergyLack) && (androidsLimitedCharging < androidsFullCharging))
	{
		androidsLimitedCharging = 0;
	}
	if ((this->otherEquipment.lifeSupportEnergyDivision.shutDownOnEnergyLack) && (lifeSupportLimitedCharging < lifeSupportFullCharging))
	{
		lifeSupportLimitedCharging = 0;
	}
	if ((this->mainframeSystem.mainframeEnergyDivision.shutDownOnEnergyLack) && (mainframeLimitedCharging < mainframeFullCharging))
	{
		mainframeLimitedCharging = 0;
	}

	double totalConsumption = deflectorsLimitedCharging +
		                      weaponsLimitedCharging +
							  tBeamLimitedCharging +
							  sensorsHRLimitedCharging +
							  sensorsLRLimitedCharging +
							  cloakingLimitedCharging +
							  androidsLimitedCharging +
							  lifeSupportLimitedCharging +
							  mainframeLimitedCharging;

	// basic flow and consumption are equal; energy in accumulator supposed
	double totalEnergyFlow  = totalConsumption;
	if (this->energeticSystem.energeticAccumulatorEnergyState.energy < totalEnergyFlow)
	{
		totalEnergyFlow = min(totalEnergyFlow, min((double)this->energeticSystem.energeticAccumulator()->actualCharging(), max(harvestingSpeed, (double)energySupplies + (double)this->energeticSystem.energeticAccumulatorEnergyState.energy)));
	}

	double deflectorsNarrowCharging  = deflectorsLimitedCharging ;
	double weaponsNarrowCharging     = weaponsLimitedCharging    ;
	double tBeamNarrowCharging       = tBeamLimitedCharging      ;
	double sensorsHRNarrowCharging   = sensorsHRLimitedCharging  ;
	double sensorsLRNarrowCharging   = sensorsLRLimitedCharging  ;
	double cloakingNarrowCharging    = cloakingLimitedCharging   ;
	double androidsNarrowCharging    = androidsLimitedCharging   ;
	double lifeSupportNarrowCharging = lifeSupportLimitedCharging;
	double mainframeNarrowCharging   = mainframeLimitedCharging  ;

	if (totalEnergyFlow < totalConsumption)
	{
		vector<map<double, pair<double *, energyDivisionClass *>>> priorityVector;
		priorityVector.clear();
		priorityVector.resize(ED_MAX_PRIORITY + 1);
		for (vector<map<double, pair<double *, energyDivisionClass *>>>::iterator litp1 = priorityVector.begin(); litp1 != priorityVector.end(); litp1++)
		{
			litp1->clear();
		}

		priorityVector[this->deflectorShields.deflectorsEnergyDivision.priority].insert(make_pair((double)this->deflectorShields.deflectorsEnergyDivision.ratio / (deflectorsNarrowCharging  + 1), make_pair(&deflectorsNarrowCharging , &(this->deflectorShields.deflectorsEnergyDivision))));
		priorityVector[this->weapons.weaponsEnergyDivision.priority            ].insert(make_pair((double)this->weapons.weaponsEnergyDivision.ratio             / (weaponsNarrowCharging     + 1), make_pair(&weaponsNarrowCharging    , &(this->weapons.weaponsEnergyDivision            ))));
		priorityVector[this->transportBeam.tBeamEnergyDivision.priority        ].insert(make_pair((double)this->transportBeam.tBeamEnergyDivision.ratio         / (tBeamNarrowCharging       + 1), make_pair(&tBeamNarrowCharging      , &(this->transportBeam.tBeamEnergyDivision        ))));
		priorityVector[this->sensors.sensorsHREnergyDivision.priority          ].insert(make_pair((double)this->sensors.sensorsHREnergyDivision.ratio           / (sensorsHRNarrowCharging   + 1), make_pair(&sensorsHRNarrowCharging  , &(this->sensors.sensorsHREnergyDivision          ))));
		priorityVector[this->sensors.sensorsLREnergyDivision.priority          ].insert(make_pair((double)this->sensors.sensorsLREnergyDivision.ratio           / (sensorsLRNarrowCharging   + 1), make_pair(&sensorsLRNarrowCharging  , &(this->sensors.sensorsLREnergyDivision          ))));
		priorityVector[this->cloaking.cloakingEnergyDivision.priority          ].insert(make_pair((double)this->cloaking.cloakingEnergyDivision.ratio           / (cloakingNarrowCharging    + 1), make_pair(&cloakingNarrowCharging   , &(this->cloaking.cloakingEnergyDivision          ))));
		priorityVector[this->mechanics.androidsEnergyDivision.priority         ].insert(make_pair((double)this->mechanics.androidsEnergyDivision.ratio          / (androidsNarrowCharging    + 1), make_pair(&androidsNarrowCharging   , &(this->mechanics.androidsEnergyDivision         ))));
		priorityVector[this->otherEquipment.lifeSupportEnergyDivision.priority ].insert(make_pair((double)this->otherEquipment.lifeSupportEnergyDivision.ratio  / (lifeSupportNarrowCharging + 1), make_pair(&lifeSupportNarrowCharging, &(this->otherEquipment.lifeSupportEnergyDivision ))));
		priorityVector[this->mainframeSystem.mainframeEnergyDivision.priority  ].insert(make_pair((double)this->mainframeSystem.mainframeEnergyDivision.ratio   / (mainframeNarrowCharging   + 1), make_pair(&mainframeNarrowCharging  , &(this->mainframeSystem.mainframeEnergyDivision  ))));

		double energyFlowLeft = totalEnergyFlow;
		for (unsigned char loop1 = ED_MAX_PRIORITY; ED_MIN_PRIORITY <= loop1; loop1--)
		{
			if (priorityVector[loop1].empty())
			{
				continue;
			}
			if (0 == energyFlowLeft)
			{
				for (map<double, pair<double *, energyDivisionClass *>>::iterator litp1 = priorityVector[loop1].begin(); litp1 != priorityVector[loop1].end(); litp1++)
				{
					(*(litp1->second.first)) = 0;
				}
				continue;
			}			
			double        priorityLevelConsumption = 0;
			unsigned long prioritySumInLevel       = 0;
			for (map<double, pair<double *, energyDivisionClass *>>::iterator litp1 = priorityVector[loop1].begin(); litp1 != priorityVector[loop1].end(); litp1++)
			{
				priorityLevelConsumption += (*(litp1->second.first));
				prioritySumInLevel       += litp1->second.second->priority;
			}
			if (energyFlowLeft < priorityLevelConsumption)
			{
				bool possibleSwitchingOff = true;
				while ((possibleSwitchingOff) && (energyFlowLeft < priorityLevelConsumption))
				{
					possibleSwitchingOff = false;
					for (map<double, pair<double *, energyDivisionClass *>>::iterator litp1 = priorityVector[loop1].begin(); litp1 != priorityVector[loop1].end(); litp1++)
					{
						if (litp1->second.second->shutDownOnEnergyLack)
						{
							priorityLevelConsumption -= (*(litp1->second.first));
							prioritySumInLevel       -= litp1->second.second->priority;
							(*(litp1->second.first))  = 0;
							possibleSwitchingOff      = true;
							break;
						}
					}
				}
			}
			if (energyFlowLeft < priorityLevelConsumption)
			{
				prioritySumInLevel = max(1, prioritySumInLevel);
				for (map<double, pair<double *, energyDivisionClass *>>::iterator litp1 = priorityVector[loop1].begin(); litp1 != priorityVector[loop1].end(); litp1++)
				{
					(*(litp1->second.first)) = min((*(litp1->second.first)), (double)litp1->second.second->priority / (double)prioritySumInLevel * (double)(energyFlowLeft));
				}
				energyFlowLeft = 0;
			}
			else
			{
				for (map<double, pair<double *, energyDivisionClass *>>::iterator litp1 = priorityVector[loop1].begin(); litp1 != priorityVector[loop1].end(); litp1++)
				{
					energyFlowLeft -= (*(litp1->second.first));
				}
			}
		}
	}

	double totalFinalDevicesConsumption = deflectorsNarrowCharging +
		                                  weaponsNarrowCharging +
										  tBeamNarrowCharging +
										  sensorsHRNarrowCharging +
										  sensorsLRNarrowCharging +
										  cloakingNarrowCharging +
										  androidsNarrowCharging +
										  lifeSupportNarrowCharging +
										  mainframeNarrowCharging;
	bool accumulatorCharging    = false;
	bool accumulatorDischarging = false;
	bool deflectorsCharging     = false;
	bool deflectorsDischarging  = false;
	bool weaponsCharging        = false;
	bool tBeamCharging          = false;
	if ((totalFinalDevicesConsumption < this->energeticSystem.energeticAccumulator()->actualCharging()) &&
		(totalFinalDevicesConsumption < energySupplies + harvestingSpeed) &&
		(this->energeticSystem.energeticAccumulatorEnergyState.energy < this->energeticSystem.energeticAccumulator()->actualAccumulator()))
	{
		accumulatorCharging = true;
	}
	if ((totalFinalDevicesConsumption > this->energeticSystem.energeticAccumulator()->actualCharging()) ||
		((totalFinalDevicesConsumption > energySupplies + harvestingSpeed) && (0 < totalFinalDevicesConsumption)))
		// if tFDC is gt actualCharging, there have to be some energy in accumulator, so it is discharging
	{
		accumulatorDischarging = true;
	}
	if (deflectorsNarrowCharging > this->deflectorShields.deflectorShieldsGenerator()->actualLeak())
		// if dNC is gt leak, there can not be full energy in shields, because it would make charging eq leak
	{
		deflectorsCharging = true;
	}
	if ((deflectorsNarrowCharging < this->deflectorShields.deflectorShieldsGenerator()->actualLeak()) &&
		(0 < this->deflectorShields.deflectorShieldsEnergyState.energy))
	{
		deflectorsDischarging = true;
	}
	if (0 < weaponsNarrowCharging)
	{
		weaponsCharging = true;
	}
	if (0 < tBeamNarrowCharging)
	{
		tBeamCharging = true;
	}
	if (0 == this->energyUpdate_)
	{
		this->energyUpdate_ = updateToATime - dv_time::encodeSeconds(1);
	}
	unsigned long long maxSecondsToChange         = dv_time::secondsBegunBetween(this->energyUpdate_, updateToATime, 1);
	unsigned long long secondsToAccumulatorChange = maxSecondsToChange;
	unsigned long long secondsToDeflectorsChange  = maxSecondsToChange;
	unsigned long long secondsToWeaponsChange     = maxSecondsToChange;
	unsigned long long secondsToTBeamChange       = maxSecondsToChange;
	unsigned long long secondsToHarvestingChange  = dv_time::secondsBegunBetween(this->energyUpdate_, harvestingChange, 1);
	secondsToHarvestingChange = max(1, secondsToHarvestingChange);
	// PREVENCE PROBLEMU: kdyby harvestingChange prisla ve stejny moment jako update, pak by update nemohl probehnout,
	// protoze by vzdy udelal krok o 0 sekund, zavolal by se znovu a cyklil by tak dlouho, dokud by ta zmena nenastala
	// v lepsim pripade; v horsim pripade by ta zmena predpokladala update energie (pravdepodobne nebude, ale co kdyz)
	// a nastal by totalni deadlock, takze cas se musi alespon o trochu posouvat; u ostatnich systemu se posunuje pres
	// ullUpRound.... nicmene tam maji take pojistku, takze pro jistotu u vsech zarizeni davama minimalne jedna (dole)
	if (accumulatorCharging)
	{
		unsigned long long accumulatorDiff = this->energeticSystem.energeticAccumulator()->actualAccumulator() - this->energeticSystem.energeticAccumulatorEnergyState.energy;
		if (0 < floor((double)this->energeticSystem.energeticAccumulator()->actualCharging() - totalFinalDevicesConsumption))
		{
			secondsToAccumulatorChange = ullUpRound((double)accumulatorDiff / ((double)this->energeticSystem.energeticAccumulator()->actualCharging() - totalFinalDevicesConsumption));
		}
		if ((0 < floor((double)this->energeticSystem.energeticAccumulator()->actualCharging())) &&
			(this->energeticSystem.energeticAccumulator()->actualCharging() > harvestingSpeed))
		{
			secondsToAccumulatorChange = min(secondsToAccumulatorChange, ullUpRound((double)(energySupplies) / (double)((this->energeticSystem.energeticAccumulator()->actualCharging() - harvestingSpeed))));
		}
	}
	if (accumulatorDischarging)
	{
		unsigned long long accumulatorDiff = this->energeticSystem.energeticAccumulatorEnergyState.energy;
		if (0 < energySupplies)
		{
			if (0 < floor(totalFinalDevicesConsumption - (double)this->energeticSystem.energeticAccumulator()->actualCharging()))
			{
				secondsToAccumulatorChange = ullUpRound((double)accumulatorDiff / (totalFinalDevicesConsumption - (double)this->energeticSystem.energeticAccumulator()->actualCharging()));
			}
			if ((0 < floor((double)this->energeticSystem.energeticAccumulator()->actualCharging())) &&
				(this->energeticSystem.energeticAccumulator()->actualCharging() > harvestingSpeed))
			{
				secondsToAccumulatorChange = min(secondsToAccumulatorChange, ullUpRound((double)(energySupplies) / (double)((this->energeticSystem.energeticAccumulator()->actualCharging() - harvestingSpeed))));
			}
		}
		else
		{
			double realChargingSpeed = min((double)this->energeticSystem.energeticAccumulator()->actualCharging(), harvestingSpeed);
			if ((0 < floor(totalFinalDevicesConsumption)) &&
				(totalFinalDevicesConsumption > realChargingSpeed))
			{
				secondsToAccumulatorChange = ullUpRound((double)accumulatorDiff / (totalFinalDevicesConsumption - realChargingSpeed));
			}
		}
	}
	if ((!(accumulatorCharging)) && (!(accumulatorDischarging)))
	{
		double realChargingSpeed = min((double)this->energeticSystem.energeticAccumulator()->actualCharging(), harvestingSpeed);
		if ((0 < floor(totalFinalDevicesConsumption)) &&
			(totalFinalDevicesConsumption > realChargingSpeed))
		{
			secondsToAccumulatorChange = ullUpRound((double)energySupplies / (totalFinalDevicesConsumption - realChargingSpeed));
		}
	}
	if (deflectorsCharging)
	{
		if (0 < floor(deflectorsNarrowCharging - (double)this->deflectorShields.deflectorShieldsGenerator()->actualLeak()))
		{
			secondsToDeflectorsChange = ullUpRound((double)deflectorsEnergyDiff / (deflectorsNarrowCharging - (double)this->deflectorShields.deflectorShieldsGenerator()->actualLeak()));
		}
	}
	if (deflectorsDischarging)
	{
		unsigned long long deflectorsDiff = this->deflectorShields.deflectorShieldsEnergyState.energy;
		if (0 < floor((double)this->deflectorShields.deflectorShieldsGenerator()->actualLeak() - deflectorsNarrowCharging))
		{
			secondsToDeflectorsChange = ullUpRound((double)deflectorsDiff / ((double)this->deflectorShields.deflectorShieldsGenerator()->actualLeak() - deflectorsNarrowCharging));
		}
	}
	if (weaponsCharging)
	{
		if (0 < floor(weaponsNarrowCharging))
		{
			secondsToWeaponsChange = ullUpRound((double)weaponsEnergyDiffToTheFire / weaponsNarrowCharging);
		}
	}
	if (tBeamCharging)
	{
		if (0 < floor(tBeamNarrowCharging))
		{
			secondsToTBeamChange = ullUpRound((double)tBeamEnergyDiff / tBeamNarrowCharging);
		}
	}
	//secondsToAccumulatorChange = max(1, secondsToAccumulatorChange);
	//secondsToDeflectorsChange  = max(1, secondsToDeflectorsChange );
	//secondsToWeaponsChange     = max(1, secondsToWeaponsChange    );
	//secondsToTBeamChange       = max(1, secondsToTBeamChange      );
	// tohle je zakomentovano, protoze kdyz maxSecondsToChange je 0, tak tyhle budou 1, coz vyvola zbytecny posun o 1
	unsigned long long secondsShift         = min(min(min(min(min(maxSecondsToChange, secondsToAccumulatorChange), secondsToDeflectorsChange), secondsToWeaponsChange), secondsToTBeamChange), secondsToHarvestingChange);
	unsigned long long secondsToChangeAfter = MAX_SECONDS_BETWEEN_ENERGETIC_PHASES + secondsShift;
	if (secondsShift < secondsToAccumulatorChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToAccumulatorChange);
	}
	if (secondsShift < secondsToDeflectorsChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToDeflectorsChange);
	}
	if (secondsShift < secondsToWeaponsChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToWeaponsChange);
	}
	if (secondsShift < secondsToTBeamChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToTBeamChange);
	}
	if (secondsShift < secondsToHarvestingChange)
	{
		secondsToChangeAfter = min(secondsToChangeAfter, secondsToHarvestingChange);
	}
	secondsToChangeAfter = max(1, secondsToChangeAfter);
	if (accumulatorCharging)
	{
		unsigned long long energyAddition = (unsigned long long)((double)secondsShift * ((double)this->energeticSystem.energeticAccumulator()->actualCharging() - (double)totalFinalDevicesConsumption));
		unsigned long long ceiling        = min(this->energeticSystem.energeticAccumulator()->actualAccumulator(), this->energeticSystem.energeticAccumulatorEnergyState.targetEnergy);
		                   energyAddition = min(energyAddition, ceiling - this->energeticSystem.energeticAccumulatorEnergyState.energy);
		this->energy_ = dSafeSub(this->energy_, (double)energyAddition);
		this->energy_ = dSafeSub(this->energy_, (double)secondsShift * totalFinalDevicesConsumption);
		this->energeticSystem.energeticAccumulatorEnergyState.energy += energyAddition;
	}
	if (accumulatorDischarging)
	{
		unsigned long long energyDecrease = (unsigned long long)(secondsShift * (totalFinalDevicesConsumption - this->energeticSystem.energeticAccumulator()->actualCharging()));
		if (((double)secondsShift * (double)this->energeticSystem.energeticAccumulator()->actualCharging()) > (double)energySupplies)
		{
			energyDecrease += (unsigned long long)(((double)secondsShift * (double)this->energeticSystem.energeticAccumulator()->actualCharging()) - (double)energySupplies);
			this->energy_   = 0;
		}
		else
		{
			this->energy_   = dSafeSub(this->energy_, (double)secondsShift * (double)this->energeticSystem.energeticAccumulator()->actualCharging());
		}
		energyDecrease = min(energyDecrease, this->energeticSystem.energeticAccumulatorEnergyState.energy);
		this->energeticSystem.energeticAccumulatorEnergyState.energy -= energyDecrease;
	}
	if ((!(accumulatorCharging)) && (!(accumulatorDischarging)))
	{
		this->energy_ = dSafeSub(this->energy_, (double)secondsShift * (double)totalFinalDevicesConsumption);
	}
	this->energeticSystem.setGradient(dSafeSub((double)this->energeticSystem.energeticAccumulator()->actualCharging(), (double)totalFinalDevicesConsumption));
	if (deflectorsCharging)
	{
		unsigned long long energyAddition = (unsigned long long)(secondsShift * (deflectorsNarrowCharging - this->deflectorShields.deflectorShieldsGenerator()->actualLeak()));
		unsigned long long ceiling        = min(this->deflectorShields.deflectorShieldsGenerator()->actualAccumulator(), this->deflectorShields.deflectorShieldsEnergyState.targetEnergy);
		                   energyAddition = min(energyAddition, ceiling - this->deflectorShields.deflectorShieldsEnergyState.energy);
		this->deflectorShields.deflectorShieldsEnergyState.energy += energyAddition;
	}
	if (deflectorsDischarging)
	{
		unsigned long long energyDecrease = (unsigned long long)(secondsShift * (this->deflectorShields.deflectorShieldsGenerator()->actualLeak() - deflectorsNarrowCharging));
		                   energyDecrease = min(energyDecrease, this->deflectorShields.deflectorShieldsEnergyState.energy);
		this->deflectorShields.deflectorShieldsEnergyState.energy -= energyDecrease;
	}
	if (weaponsCharging)
	{
		unsigned long long energyAddition = (unsigned long long)(secondsShift * weaponsNarrowCharging);
		this->chargeWeaponsAndFireIfItIsToBe(energyAddition, secondsShift);
	}
	if (tBeamCharging)
	{
		unsigned long long energyAddition = (unsigned long long)(secondsShift * tBeamNarrowCharging);
		unsigned long long ceiling        = min(this->transportBeam.transportBeamGenerator()->actualAccumulator(), this->transportBeam.tBeamEnergyState.targetEnergy);
		                   energyAddition = min(energyAddition, ceiling - this->transportBeam.tBeamEnergyState.energy);
		this->transportBeam.tBeamEnergyState.energy += energyAddition;
	}

	//if (0 == secondsShift)
	//{
	//	errLogicalError("fortress_skelet", "fortressClass.energyDistributionPhaseAndWeaponFire", "no shifting", (unsigned long long)this->getID());
	//	secondsShift++;
	//}

	this->deflectorShields.setNarrowCharging(deflectorsNarrowCharging);

	this->weapons.setNarrowCharging(weaponsNarrowCharging);

	this->transportBeam.setNarrowCharging(tBeamNarrowCharging);

	if (sensorsHRNarrowCharging < this->sensors.highResolutionSensors()->actualConsumption())
	{
		this->sensors.sensorsHRPowerState.energyLack();
	}
	else
	{
		this->sensors.sensorsHRPowerState.enoughEnergy();
	}
	this->sensors.sensorsHRPowerState.setNarrowCharging(sensorsHRNarrowCharging);

	if (sensorsLRNarrowCharging < this->sensors.longRangeSensors()->actualConsumption())
	{
		this->sensors.sensorsLRPowerState.energyLack();
	}
	else
	{
		this->sensors.sensorsLRPowerState.enoughEnergy();
	}
	this->sensors.sensorsLRPowerState.setNarrowCharging(sensorsLRNarrowCharging);

	if (cloakingNarrowCharging < this->cloaking.cloakingDevice()->actualConsumption())
	{
		this->cloaking.cloakingPowerState.energyLack();
	}
	else
	{
		this->cloaking.cloakingPowerState.enoughEnergy();
	}
	this->cloaking.cloakingPowerState.setNarrowCharging(cloakingNarrowCharging);

	if (androidsNarrowCharging < this->mechanics.androids()->actualConsumption(this->realmID_))
	{
		this->mechanics.androidsPowerState.energyLack();
	}
	else
	{
		this->mechanics.androidsPowerState.enoughEnergy();
	}
	this->mechanics.androidsPowerState.setNarrowCharging(androidsNarrowCharging);

	if (lifeSupportNarrowCharging < this->otherEquipment.lifeSupport()->actualConsumption(this->crew.getTotalCrewCount()))
	{
		this->lifeSupportNarrowDueToEnergyLack(lifeSupportNarrowCharging);
	}
	this->otherEquipment.setNarrowCharging(lifeSupportNarrowCharging);

	if (mainframeNarrowCharging < this->mainframeSystem.mainframe()->actualConsumption())
	{
		this->switchOffMainframeDueToEnergyLack();
	}
	this->mainframeSystem.setNarrowCharging(mainframeNarrowCharging);

	double positiveGradientPart = harvestingSpeed;
	double negativeGradientPart = min(min(max((double)this->energy_, (double)positiveGradientPart), (double)totalConsumption), (double)this->energeticSystem.energeticAccumulator()->actualCharging());
	if (this->energeticSystem.energeticAccumulatorEnergyState.energy < min(this->energeticSystem.energeticAccumulatorEnergyState.targetEnergy, this->energeticSystem.energeticAccumulator()->actualAccumulator()))
	{
		negativeGradientPart = min(max((double)this->energy_, (double)positiveGradientPart), (double)this->energeticSystem.energeticAccumulator()->actualCharging());
	}
	this->energyGradient_ = positiveGradientPart - negativeGradientPart;

	this->energy_ = min(max(energy_, 0), this->energyLimitInTeraJoules());

	dv_time::datetime timeShift    = dv_time::encodeSeconds(secondsShift);
	dv_time::datetime changeAfter  = dv_time::encodeSeconds(secondsToChangeAfter) + this->energyUpdate_;
	this->energyUpdate_           += timeShift;

#ifdef DEBUG_URZA
	if ((DEBUG_URZA_FORTRESS == this->getID()) || (0 == DEBUG_URZA_FORTRESS))
	{
		debugOut <<
		"shift " << secondsShift << 
		"; next " << secondsToChangeAfter << 
		"; change " << maxSecondsToChange <<
		"; acc " << secondsToAccumulatorChange <<
		"; def " << secondsToDeflectorsChange <<
		"; har " << secondsToHarvestingChange <<
		"; tbm " << secondsToTBeamChange <<
		"; wep " << secondsToWeaponsChange <<
		endl << "..:: EP.END ::.." << endl << endl;
	}
#endif

	if (this->energyUpdate_ < updateToATime)
	{
#ifdef DEBUG_URZA
		debugOut << "(rec) ";
#endif
		return this->energyDistributionPhaseAndWeaponsFire(updateToATime);
	}
	else
	{
		return changeAfter;
	}
};

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

void fortressClass::energyDistributionPhaseAndWeaponsFire(bool doubleUpdate)
{
	dv_time::datetime actualGameTime = wt2gt(dv_time::now());

	unsigned long long totalUpdatingSeconds = dv_time::secondsBegunBetween(this->energyUpdate_, actualGameTime, 1);
	this->mechanics.repairingPhase(this, totalUpdatingSeconds);
	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		for (dtIdentifierDeque::const_iterator litp1 = thisBase->hangarsPort.beginHangarsIdentifiers(); litp1 != thisBase->hangarsPort.endHangarsIdentifiers(); litp1++)
		{
			thisBase->hangarsPort.hangarByIdentifier(*(litp1))->checkConstruction(this);
		}
	}

	if (doubleUpdate)
	{
		energyDistributionPhaseAndWeaponsFire(actualGameTime);
	}
	dv_time::datetime nextUpdate = energyDistributionPhaseAndWeaponsFire(actualGameTime);

	unsigned long long secondsToTheNextRepair = this->mechanics.repairingDistribution(this, dv_time::secondsBegunBetween(actualGameTime, nextUpdate, 1));
	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		for (dtIdentifierDeque::const_iterator litp1 = thisBase->hangarsPort.beginHangarsIdentifiers(); litp1 != thisBase->hangarsPort.endHangarsIdentifiers(); litp1++)
		{
			thisBase->hangarsPort.hangarByIdentifier(*(litp1))->checkConstruction(this);
		}
	}
	
	nextUpdate = min(nextUpdate, actualGameTime + dv_time::encodeSeconds(secondsToTheNextRepair));

	if ((nextUpdate < energyTrigger_) || (energyTrigger_ < actualGameTime + dv_time::encodeSeconds(1)))
	// novy trigger se nastavuje bud v pripade, ze je aktualnejsi nez doposud nastaveny,
	// nebo v pripade, ze nejaktualnejci trigger byl prave aktivovan (ta sekunda je tam pro jistotu)
	{
		gctx.eng.registerEvent(nextUpdate, new energyDistributionPhaseAndWeaponFireTriggerClass(this->getID()),
            energyDistributionPhaseAndWeaponFireTriggerIdentificator_);
		energyTrigger_ = nextUpdate;
	}
};

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

void fortressClass::aimNewTarget(dtIdentifier newTargetID, bool suppressEnergyPhase)
{
	if ((newTargetID == this->targetOfWeapons_) ||
		(newTargetID == this->getID()         ))
	{
		return;
	}
	lastTargetAimTime_ = wt2gt(dv_time::now());

	fortressClass * oldTarget = actx->cacheFortressesList.getItem<fortressClass>(this->targetOfWeapons_);
	if (oldTarget)
	{
		this->ourWeaponsUnlocked(oldTarget);
		oldTarget->enemyWeaponsUnlocked(this);
		oldTarget->subAttackerThatLockedOnThis(this->getID());
	}

	if (!suppressEnergyPhase)
	{
		this->energyDistributionPhaseAndWeaponsFire();
	}
	this->weapons.dischargeAllWeapons();

	fortressClass * newTarget = actx->cacheFortressesList.getItem<fortressClass>(newTargetID);
	if ((!newTarget                 ) ||
		(NOT_VALID_ID == newTargetID))
	{
		this->targetOfWeapons_ = newTargetID;
		if (!suppressEnergyPhase)
		{
			this->energyDistributionPhaseAndWeaponsFire();
		}
		return;
	}

	if (suppressEnergyPhase)
	{
		errExceptionError("Aiming not NULL target with energyPhase suppressed; wtf?? NULL has been aimed to prevent cycling.");
		this->targetOfWeapons_ = NOT_VALID_ID;
		return;
	}

	if (!(this->isInRangeForAttack(newTarget)))
	{
		this->targetOfWeapons_ = NOT_VALID_ID;
		this->energyDistributionPhaseAndWeaponsFire();
		return;
	}

	this->targetOfWeapons_ = newTargetID;

	this->suppressWeaponsLockOnWarningTEMP_ = 1;
	newTarget->addAttackerThatLockedOnThis(this->getID());
	this->energyDistributionPhaseAndWeaponsFire();
	this->suppressWeaponsLockOnWarningTEMP_ = 0;

	if (newTargetID == this->targetOfWeapons_)
	{
		this->ourWeaponsLockedOnEnemy(newTarget);
		if (newTarget->isInRangeForScanning(this))
		{
			newTarget->enemyWeaponsLockedOnWarning(this);
		}
	}
	else
	{
		newTarget = actx->cacheFortressesList.getItem<fortressClass>(newTargetID);
		// znovu nacist ten newTarget je treba proto, ze by hypoteticky mohlo dojit k anihilaci hned na prvni pokus
		// pokud byl newTarget anihilovan, vrati to ted NULL, takze na to nesahnu, pokud to tam neni
		if (newTarget)
		{
			newTarget->subAttackerThatLockedOnThis(this->getID());
		}
	}
};

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

void fortressClass::targetAnnihilated()
{
	if (NOT_VALID_ID == this->targetOfWeapons_)
	{
		return;
	}
	lastTargetAimTime_ = wt2gt(dv_time::now());	

	fortressClass * oldTarget = actx->cacheFortressesList.getItem<fortressClass>(this->targetOfWeapons_);
	if (oldTarget)
	{
		this->weaponsTargetHasBeenAnnihilated(oldTarget);
	}

	this->targetOfWeapons_ = NOT_VALID_ID;

	this->weapons.dischargeAllWeapons();
	this->energyDistributionPhaseAndWeaponsFire();
};

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

void fortressClass::targetOutOfRange(bool suppressEnergyPhase)
{
	if (NOT_VALID_ID == this->targetOfWeapons_)
	{
		return;
	}

	this->weapons.dischargeAllWeapons(); 
	this->aimNewTarget((dtIdentifier)NOT_VALID_ID, suppressEnergyPhase);

	fortressClass * oldTarget = actx->cacheFortressesList.getItem<fortressClass>(this->targetOfWeapons_);

	if (!(this->suppressWeaponsLockOnWarningTEMP_))
	{
		this->ourWeaponsUnlocked(oldTarget);
		if (oldTarget)
		{
			oldTarget->enemyWeaponsUnlocked(this);
			oldTarget->subAttackerThatLockedOnThis(this->getID());
		}
	}
};

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

void fortressClass::chargeWeaponsAndFireIfItIsToBe(unsigned long long moreEnergy, unsigned long long seconds)
{
	if ((0 == moreEnergy) || (NOT_VALID_ID == this->targetOfWeapons_))
	{
		return;
	}
	if (this->isAttackPrevented())
	{
		this->targetOutOfRange(1);
		return;
	}

	bool targetInRange               = 0;

	unsigned long long wepAccept     = 0;
	unsigned long long canAccept     = this->weapons.getTotalWeaponsCharging(this, &wepAccept) * seconds;
	unsigned long long tryAccept     = moreEnergy;
	unsigned long long truAccept     = min(canAccept, tryAccept);
	double             chargingRatio = (double)truAccept / ((double)wepAccept * (double)seconds);

	unsigned long long distanceToTheTarget = 0;
	dist_t             distance            = 0;
	bool               isInSomeRange       = this->getDistanceToTheWeaponsTarget(distance);
	if (isInSomeRange)
	{
		distanceToTheTarget = ullUpRound(distance);
	}
	else
	{
		this->targetOutOfRange(1);
		return;
	}

	droneMissileLauncherPEnergyStatePPair dml;
	for (unsigned long loop1 = 0; NULL != ((dml = this->weapons.droneMissileLaunchers(loop1)).first); loop1++)
	{
		if (this->weapons.isWeaponCharging(this, dml.first, dml.second))
		{
			if (distanceToTheTarget <= this->weapons.droneMissiles()->actualRange(this->realmID_))
			{
				targetInRange = 1;
			}
			dml.second->energy                     = min(dml.second->energy, this->weapons.weaponFireLimit(this, dml.first, dml.second));
			unsigned long long deviceFreeCapacity  = this->weapons.energyToWeaponFireLimit(this, dml.first, dml.second);
			unsigned long long shouldBeCharged     = ullUpRound((double)seconds * chargingRatio * (double)dml.first->actualCharging());
			unsigned long long canBeCharged        = min(min(shouldBeCharged, deviceFreeCapacity), moreEnergy);
			moreEnergy                            -= canBeCharged;
			dml.second->energy                    += canBeCharged;
			if ((0 < this->weapons.droneMissiles()->getWorking()                                                                          ) && 
				(this->weapons.droneMissiles()->actualLaunch(this->realmID_) <= (dml.second->energy + this->weapons.getWeaponsCount())    ) &&
				(distanceToTheTarget                                         <= this->weapons.droneMissiles()->actualRange(this->realmID_)))
				// kvuli zaokrouhleni je mozne vypalit i s trochu mensi energii, aby to vyslo i v pripade spatneho zaokrouhleni
			{
				this->attackFortress(actx->cacheFortressesList.getItem<fortressClass>(targetOfWeapons_), ATTACK_TYPE_DRONES, loop1);
			}
		}
		else
		{
			dml.second->energy = 0;
		}
		dml.second->energy                         = min(dml.second->energy, this->weapons.weaponFireLimit(this, dml.first, dml.second));
	}
	laserGunPEnergyStatePPair lg;
	for (unsigned long loop1 = 0; NULL != ((lg = this->weapons.laserGuns(loop1)).first); loop1++)
	{
		if (this->weapons.isWeaponCharging(this, lg.first, lg.second))
		{
			if (distanceToTheTarget <= lg.first->actualRange())
			{
				targetInRange = 1;
			}
			lg.second->energy                      = min(lg.second->energy, this->weapons.weaponFireLimit(this, lg.first, lg.second));
			unsigned long long deviceFreeCapacity  = this->weapons.energyToWeaponFireLimit(this, lg.first, lg.second);
			unsigned long long shouldBeCharged     = ullUpRound((double)seconds * chargingRatio * (double)lg.first->actualCharging());
			unsigned long long canBeCharged        = min(min(shouldBeCharged, deviceFreeCapacity), moreEnergy);
			moreEnergy                            -= canBeCharged;
			lg.second->energy                     += canBeCharged;
			if ((this->weapons.weaponFireLimit(this, lg.first, lg.second) <= (lg.second->energy + this->weapons.getWeaponsCount())) &&
				(distanceToTheTarget                                      <= lg.first->actualRange()                              ))
				// kvuli zaokrouhleni je mozne vypalit i s trochu mensi energii, aby to vyslo i v pripade spatneho zaokrouhleni
			{
				this->attackFortress(actx->cacheFortressesList.getItem<fortressClass>(targetOfWeapons_), ATTACK_TYPE_LASER, loop1);
			}
		}
		else
		{
			lg.second->energy = 0;
		}
		lg.second->energy                          = min(lg.second->energy, this->weapons.weaponFireLimit(this, lg.first, lg.second));
	}

	if (!targetInRange)
	{
		this->targetOutOfRange(1);
	};
};

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

unsigned long long fortressClass::getTotalWeaponsEnergyDiffToTheFire()
{
	if (this->isAttackPrevented())
	{
		this->targetOutOfRange(1);
		return 0;
	}
	if (NOT_VALID_ID == this->targetOfWeapons_)
	{
		this->weapons.dischargeAllWeapons();
		return 0;
	}
	dist_t             distance              = 0;
	unsigned long long distanceToTheTarget   = 0;
	bool isTargetInSomeRange = this->getDistanceToTheWeaponsTarget(distance);
	if (isTargetInSomeRange)
	{
		distanceToTheTarget = ullUpRound(distance);
	}
	else
	{
		this->targetOutOfRange(1);
		return 0;
	}

	unsigned long long secondsToTheFirstFire = 0;
	bool               targetInRange         = 0;
	
	droneMissileLauncherPEnergyStatePPair dml;
	for (unsigned long loop1 = 0; NULL != ((dml = this->weapons.droneMissileLaunchers(loop1)).first); loop1++)
	{
		if (this->weapons.isWeaponCharging(this, dml.first, dml.second))
		{
#ifdef DEBUG_URZA
			if ((DEBUG_URZA_FORTRESS == this->getID()) || (0 == DEBUG_URZA_FORTRESS))
			{
				debugOut << "DML (" << dml.first->getID() << "):" << dml.first->actualAccumulator() << " / " << dml.first->actualCharging() << " / " << this->weapons.droneMissiles()->actualLaunch(this->realmID_) << " / " << dml.second->energy << " / " << dml.second->targetEnergy << endl;
			}
#endif
			if (distanceToTheTarget <= this->weapons.droneMissiles()->actualRange(this->realmID_))
			{
				targetInRange = 1;
			}
			unsigned long long secondsToFire = ullUpRoundDiv(this->weapons.energyToWeaponFireLimit(this, dml.first, dml.second), dml.first->actualCharging());
			if ((0 < secondsToTheFirstFire) && (0 < secondsToFire))
			{
				secondsToTheFirstFire = min(secondsToTheFirstFire, secondsToFire);
			}
			else
			{
				secondsToTheFirstFire = max(secondsToTheFirstFire, secondsToFire);
			}
		} 
		else
		{
			dml.second->energy = 0;
		}
	}

	laserGunPEnergyStatePPair lg;
	for (unsigned long loop1 = 0; NULL != ((lg = this->weapons.laserGuns(loop1)).first); loop1++)
	{
		if (this->weapons.isWeaponCharging(this, lg.first, lg.second))
		{
#ifdef DEBUG_URZA
			if ((DEBUG_URZA_FORTRESS == this->getID()) || (0 == DEBUG_URZA_FORTRESS))
			{
				debugOut << "LG (" << lg.first->getID() << "):" << lg.first->actualAccumulator() << " / " << lg.first->actualCharging() << " / " << lg.second->targetEnergy << " / " << lg.second->energy << endl;
			}
#endif
			if (distanceToTheTarget <= lg.first->actualRange())
			{
				targetInRange = 1;
			}
			unsigned long long secondsToFire = ullUpRoundDiv(this->weapons.energyToWeaponFireLimit(this, lg.first, lg.second), lg.first->actualCharging());
			if ((0 < secondsToTheFirstFire) && (0 < secondsToFire))
			{
				secondsToTheFirstFire = min(secondsToTheFirstFire, secondsToFire);
			}
			else
			{
				secondsToTheFirstFire = max(secondsToTheFirstFire, secondsToFire);
			}
		}
		else
		{
			lg.second->energy = 0;
		}
	}

	if (!targetInRange)
	{
		this->targetOutOfRange(1);
		return 0;
	};

	if (0 < secondsToTheFirstFire)
	{
		unsigned long long result = 0;
		for (unsigned long loop1 = 0; NULL != ((dml = this->weapons.droneMissileLaunchers(loop1)).first); loop1++)
		{
			if (this->weapons.isWeaponCharging(this, dml.first, dml.second))
			{
				result += secondsToTheFirstFire * dml.first->actualCharging();
			}			
		}
		for (unsigned long loop1 = 0; NULL != ((lg = this->weapons.laserGuns(loop1)).first); loop1++)
		{
			if (this->weapons.isWeaponCharging(this, lg.first, lg.second))
			{
				result += secondsToTheFirstFire * lg.first->actualCharging();
			}
		}
#ifdef DEBUG_URZA
			if ((DEBUG_URZA_FORTRESS == this->getID()) || (0 == DEBUG_URZA_FORTRESS))
			{
				debugOut << "DIFF: " << result << endl;
			}
#endif
		return result;
	}
	else
	{
		return 0;
	}
}

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

void fortressClass::addAllResources(unsigned long long QGP, unsigned long long ulr, unsigned long long HeW, unsigned long long deu, unsigned long long ZrC, unsigned long long eng, unsigned long long ilm, unsigned long long tit)
{
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();

	this->quarkGluonPlasma_ += QGP;
	this->ulrea_            += ulr;
	this->heavyWater_       += HeW;
	this->deuterium_        += deu;
	this->zirconiumCrystal_ += ZrC;
	this->energy_           += eng;
	this->ilmenite_         += ilm;
	this->titanium_         += tit;

	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
}

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

void fortressClass::subAllResources(unsigned long long &QGP, unsigned long long &ulr, unsigned long long &HeW, unsigned long long &deu, unsigned long long &ZrC, unsigned long long &eng, unsigned long long &ilm, unsigned long long &tit)
{
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();

	QGP = min(QGP, (unsigned long long)this->quarkGluonPlasma_);
	ulr = min(ulr, (unsigned long long)this->ulrea_           );
	HeW = min(HeW, (unsigned long long)this->heavyWater_      );
	deu = min(deu, (unsigned long long)this->deuterium_       );
	ZrC = min(ZrC, (unsigned long long)this->zirconiumCrystal_);
	eng = min(eng, (unsigned long long)this->energy_          );
	ilm = min(ilm, (unsigned long long)this->ilmenite_        );
	tit = min(tit, (unsigned long long)this->titanium_        );

	this->quarkGluonPlasma_ -= (double)QGP;
	this->ulrea_            -= (double)ulr;
	this->heavyWater_       -= (double)HeW;
	this->deuterium_        -= (double)deu;
	this->zirconiumCrystal_ -= (double)ZrC;
	this->energy_           -= (double)eng;
	this->ilmenite_         -= (double)ilm;
	this->titanium_         -= (double)tit;

	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
}

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

unsigned long long fortressClass::addTitaniumDirectlyToTheShell(unsigned long long & kgs)
{
	if ((FT_BASE != this->getFortressType()) || (this->isConstructed(0)))
	{
		return 0;
	}
	
	this->energyDistributionPhaseAndWeaponsFire();
	kgs = min(kgs, ((baseClass *)(this))->maxTitaniumShellCanAccept());
	this->titanium_ += (double)(kgs);
	this->energyDistributionPhaseAndWeaponsFire();
	
	return (unsigned long long)(this->titanium_); };

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

unsigned short fortressClass::decStructuralIntegrityAndReturnPercOfDamage(unsigned long structuralIntegrityLoss)
{
	unsigned short initialIntegrityPerc = (unsigned short)((100 * structuralIntegrity_) / ullHandleZero(totalStructuralIntegrity_));

	structuralIntegrity_                = ullSafeSub(structuralIntegrity_, structuralIntegrityLoss);

	unsigned short finalIntegrityPerc   = (unsigned short)((100 * structuralIntegrity_) / ullHandleZero(totalStructuralIntegrity_));

	return (initialIntegrityPerc - finalIntegrityPerc);
}

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

unsigned long fortressClass::fireDroneMissile(unsigned long launcherPos)
{
	droneMissileLauncherPEnergyStatePPair   launcherWithState = this->weapons.droneMissileLaunchers(launcherPos);
	droneMissileLauncherClass             * launcher          = launcherWithState.first;
	energyStateClass                      * state             = launcherWithState.second;
	
	this->weapons.droneMissiles()->subWorking(1);
	state->energy = ullSafeSub(state->energy, this->weapons.droneMissiles()->actualLaunch(this->realmID_));
	return this->weapons.droneMissiles()->actualDamage(this->realmID_);
}

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

unsigned long fortressClass::fireLaser(unsigned long laserGunPos)
{
	laserGunPEnergyStatePPair   laserGunWithState = this->weapons.laserGuns(laserGunPos);
	laserGunClass             * laserGun          = laserGunWithState.first;
	energyStateClass          * state             = laserGunWithState.second;

	unsigned long result = (unsigned long)(state->energy);
	state->energy        = 0;
	return result;
}

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

unsigned long fortressClass::fireTBeam()
{
	unsigned long result                        = (unsigned long)(this->transportBeam.tBeamEnergyState.energy);
	this->transportBeam.tBeamEnergyState.energy = 0;
	return result;
}

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

void fortressClass::energeticSystemDamage(unsigned short damagedShardPerc)
{
	if (this->energeticSystem.energeticAccumulator())
		this->energeticSystem.energeticAccumulator()->harm(damagedShardPerc);

	if (this->energeticSystem.energeticAccumulator()->isTotallyDevastated())
	{
		this->getFortressRealm()->mainframeFailure(this);
	}
}

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

void fortressClass::mainframeDamage(unsigned short damagedShardPerc)
{
	if (this->mainframeSystem.mainframe())
		this->mainframeSystem.mainframe()->harm(damagedShardPerc);

	if (this->mainframeSystem.mainframe()->isTotallyDevastated())
	{
		this->getFortressRealm()->mainframeFailure(this);
	}
}

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

void fortressClass::deflectorShieldsDamage(unsigned short damagedShardPerc)
{
	if (this->deflectorShields.deflectorShieldsGenerator())
		this->deflectorShields.deflectorShieldsGenerator()->harm(damagedShardPerc);
}

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

void fortressClass::weaponsDamage(unsigned short damagedShardPerc)
{
	if (this->weapons.weaponEnergyCircuit())
		this->weapons.weaponEnergyCircuit()->harm(damagedShardPerc);
	unsigned long loop1 = 0;
	while (this->weapons.droneMissileLaunchersOnly(loop1))	
		this->weapons.droneMissileLaunchersOnly(loop1++)->harm(damagedShardPerc);
	if (this->weapons.droneMissiles())
		this->weapons.droneMissiles()->harm(damagedShardPerc);
	loop1 = 0;
	while (this->weapons.laserGunsOnly(loop1))
		this->weapons.laserGunsOnly(loop1++)->harm(damagedShardPerc);
}

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

void fortressClass::transportBeamDamage(unsigned short damagedShardPerc)
{
	if (this->transportBeam.transportBeamGenerator())
		this->transportBeam.transportBeamGenerator()->harm(damagedShardPerc);
}

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

void fortressClass::androidsDamage(unsigned short damagedShardPerc)
{
	if (this->mechanics.androids())
		this->mechanics.androids()->harm(damagedShardPerc);
}

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

void fortressClass::crewDamage(unsigned short damagedShardPerc)
{
	unsigned long ablesDocs = this->crew.getEffectiveCountOf(CREW_DOCTOR);
	for (unsigned short loop1 = 0; loop1 < CREW_COUNT_TOTAL; loop1++)
	{
		// vypocty zranenych
		unsigned long totalCount = this->crew.getTotalCountOf(loop1);
		unsigned long woundedCount;
		if (totalCount < ROUNDING_ERROR_LIMIT)
		{
			woundedCount = 0;
			for (unsigned long loop2 = 0; loop2 < totalCount; loop2++)
			{
				(rollADice((double)damagedShardPerc / (double)100)) && (woundedCount++);
			}
		}
		else
		{
			woundedCount = ulUpRoundDiv(totalCount * damagedShardPerc, 100);
		}
		this->crew.woundSome(loop1, woundedCount);
		// vypocty adeptu na smrt - je to procento ze zranenych a toto procento se zvysuje s poskozenim (logicky, protoze jsou vaznejsi zraneni)
		unsigned long fateAdept;
		if (woundedCount < ROUNDING_ERROR_LIMIT)
		{
			fateAdept = 0;
			for (unsigned long loop2 = 0; loop2 < woundedCount; loop2++)
			{
				(rollADice((double)damagedShardPerc / (double)100)) && (fateAdept++);
			}
		}
		else
		{
			fateAdept = ulUpRoundDiv(woundedCount * damagedShardPerc, 100);
		}
		// zachrana zranenych
		unsigned long firstAidDocs = min(ablesDocs, fateAdept); // kolik doktoru pomaha pred smrti
		ablesDocs -= firstAidDocs; // tolik doktoru uz nemuze pomahat jinym
		unsigned long fatalities = fateAdept - firstAidDocs; // adepti na smrt bez pomoci doktoru umiraji
		fateAdept -= fatalities; // adeptu na smrt je mene o ty, kteri umreli
		if (fateAdept < ROUNDING_ERROR_LIMIT)
		{
			for (unsigned long loop2 = 0; loop2 < fateAdept; loop2++)
			{
				(rollADice((double)1 - DOC_RES_CHANCE)) && (fatalities++);
			}
		}
		else
		{
			fatalities += (unsigned long)ceil((double)fateAdept * ((double)1 - DOC_RES_CHANCE));
		}
		// odepsani mrtvych (mrtvi se stavaji z ranenych)
		this->crew.killSomeWounded(loop1, fatalities);
	}
}

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

void fortressClass::miningDevicesDamage(unsigned short damagedShardPerc)
{
	if (this->miningDevices.magneticalCollectorsOfPlasma())
		this->miningDevices.magneticalCollectorsOfPlasma()->harm(damagedShardPerc);
	if (this->miningDevices.submersibleFiltrationTank())
		this->miningDevices.submersibleFiltrationTank()->harm(damagedShardPerc);
	if (this->miningDevices.submarineMiningMachine())
		this->miningDevices.submarineMiningMachine()->harm(damagedShardPerc);
	if (this->miningDevices.undergroundDrillingMachine())
		this->miningDevices.undergroundDrillingMachine()->harm(damagedShardPerc);
}

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

void fortressClass::sensorsDamage(unsigned short damagedShardPerc)
{
	if (this->sensors.highResolutionSensors())
		this->sensors.highResolutionSensors()->harm(damagedShardPerc);
	if (this->sensors.longRangeSensors())
		this->sensors.longRangeSensors()->harm(damagedShardPerc);
}

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

void fortressClass::probesDamage(unsigned short damagedShardPerc)
{
	unsigned long loop1 = 0;
	while (this->probeDevices.probes(loop1))
		this->probeDevices.probes(loop1++)->harm(damagedShardPerc);
}

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

void fortressClass::otherEquipmentDamage(unsigned short damagedShardPerc)
{
	if (this->otherEquipment.plasmaFilter())
		this->otherEquipment.plasmaFilter()->harm(damagedShardPerc);
	if (this->otherEquipment.scientificLab())
		this->otherEquipment.scientificLab()->harm(damagedShardPerc);
	if (this->otherEquipment.lifeSupport())
		this->otherEquipment.lifeSupport()->harm(damagedShardPerc);
	if (this->otherEquipment.subspaceTransmitter())
		this->otherEquipment.subspaceTransmitter()->harm(damagedShardPerc);
}
	
// --------------------------------

void fortressClass::cloakingDeviceDamage(unsigned short damagedShardPerc)
{
	if (this->cloaking.cloakingDevice())
		this->cloaking.cloakingDevice()->harm(damagedShardPerc);
}

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

void fortressClass::payloadDamage(unsigned short damagedShardPerc)
{
	if (this->warehouse.magneticalGrid())
		this->warehouse.magneticalGrid()->harm(damagedShardPerc);
	if (this->warehouse.transportContainer())
		this->warehouse.transportContainer()->harm(damagedShardPerc);
	if (this->warehouse.energeticCell())
		this->warehouse.energeticCell()->harm(damagedShardPerc);
}

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

void baseClass::hangarsDamage(unsigned short damagedShardPerc)
{
	unsigned long loop1 = 0;
	while (this->hangarsPort.hangars(loop1))
		this->hangarsPort.hangars(loop1++)->harm(damagedShardPerc);
}

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

void baseClass::factoriesDamage(unsigned short damagedShardPerc)
{
	if (this->factories.magneticalFilter())
		this->factories.magneticalFilter()->harm(damagedShardPerc);
	if (this->factories.deuteriumDecomposer())
		this->factories.deuteriumDecomposer()->harm(damagedShardPerc);
	if (this->factories.zirconiumReactor())
		this->factories.zirconiumReactor()->harm(damagedShardPerc);
	if (this->factories.ilmeniteFurnace())
		this->factories.ilmeniteFurnace()->harm(damagedShardPerc);
}

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

void shipClass::subspaceDriveDamage(bool & annihilated)
{
	annihilated = 1;
	this->annihilate();
}

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

void shipClass::impulsDriveDamage(unsigned short damagedShardPerc)
{
	if (this->impulsDrive.impulsJetEngine())
		this->impulsDrive.impulsJetEngine()->harm(damagedShardPerc);
	if (this->impulsDrive.mechanicalDampers())
		this->impulsDrive.mechanicalDampers()->harm(damagedShardPerc);
}

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

void fortressClass::annihilate()
{
	this->thisFortressHasBeenAnnihilated(this->currentAttackerTEMP_);
	// tady byl informovan majitel lodi

	this->unlockOutAllAttackersDueToAnnihilation();
	// zde jsou informovani majitele utocicich pevnosti

	this->beforeDelete();
	// tady se poresi vsechny vesmirne veci, Osirisuv kod

	this->getFortressRealm()->removeFortress(this);
	// ted jsme prisli o vedu (mimo jine)

	this->energeticSystem.annihilate();
	this->deflectorShields.annihilate();
	this->weapons.annihilate();
	this->transportBeam.annihilate();
	this->miningDevices.annihilate();
	this->probeDevices.annihilate();
	this->sensors.annihilate();
	this->cloaking.annihilate();
	this->crew.annihilate();
	this->accommodations.annihilate();
	this->mechanics.annihilate();
	this->warehouse.annihilate();
	this->otherEquipment.annihilate();
	this->mainframeSystem.annihilate();
	// univerzalni predmety anihilovany

	if (FT_BASE == this->getFortressType())
	{
		((baseClass *)(this))->hangarsPort.annihilate();
		((baseClass *)(this))->factories.annihilate();
		// anihilovany zakladno-specificke itemy, anihilovany dokujici lode
	}
	if (FT_SHIP == this->getFortressType())
	{
		((shipClass *)(this))->subspaceDrive.annihilate();
		((shipClass *)(this))->impulsDrive.annihilate();
		// tady se anihiluji lodo-specificke predmety
		baseClass * dockingBase = ((shipClass *)(this))->getShipsDockingBase();
		if (dockingBase)
		{
			for (dtIdentifierDeque::const_iterator litp1 = dockingBase->hangarsPort.beginHangarsIdentifiers(); dockingBase->hangarsPort.endHangarsIdentifiers() != litp1; litp1++)
			{
				hangarClass * hangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
				if (this->getID() == hangar->getDockingShipID())
				{
					hangar->unboundAShip();
					break;
				}
			}
		}
		// anihilovanou lod je treba odepsat z hangaru, kde stoji
	}

	actx->cacheFortressesList.deleteItem(this->getID());
	// nakonec je smazana lod samotna, TED UZ SE NA NI NESMI SAHAT!!!!
	// tento zakaz osahavani plati i pro metody, ktere volaly annihilate()
};

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

unsigned short fortressClass::hullDeflection(unsigned long energyPassedByShields, bool & annihilated)
{
	annihilated = 0;
	if (this->isShell(0))
	{
		if (FT_BASE != this->getFortressType())
		{
			errLogicalError("Shell (ID %u) is not base!", (unsigned long long)this->getID());
			return 0;
		}
		baseClass * thisBase = (baseClass *)this;
		return thisBase->shellDeflection(energyPassedByShields);
	}

	this->globalUpdate();

	unsigned short damagePerc                    = decStructuralIntegrityAndReturnPercOfDamage(energyPassedByShields);
	unsigned short actualStructuralIntegrityPerc = (unsigned short)((100 * structuralIntegrity_) / ullHandleZero(totalStructuralIntegrity_));

	if (!(0 < structuralIntegrity_))
	{
		annihilated = 1;
		this->annihilate();
		return damagePerc;
	}

	unsigned short damagingCycles;
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_ENERGETIC_SYSTEM_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_ENERGETIC_SYSTEM_CHANCE))
		{
			energeticSystemDamage(usRollA0ToNSidedDice(HULL_DAMAGE_ENERGETIC_SYSTEM_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_MAINFRAME_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_MAINFRAME_CHANCE))
		{
			mainframeDamage(usRollA0ToNSidedDice(HULL_DAMAGE_MAINFRAME_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_DEFLECTOR_SHIELDS_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_DEFLECTOR_SHIELDS_CHANCE))
		{
			deflectorShieldsDamage(usRollA0ToNSidedDice(HULL_DAMAGE_DEFLECTOR_SHIELDS_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_WEAPONS_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_WEAPONS_CHANCE))
		{
			weaponsDamage(usRollA0ToNSidedDice(HULL_DAMAGE_WEAPONS_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_TRANSPORT_BEAM_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_TRANSPORT_BEAM_CHANCE))
		{
			transportBeamDamage(usRollA0ToNSidedDice(HULL_DAMAGE_TRANSPORT_BEAM_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_ANDROIDS_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_ANDROIDS_CHANCE))
		{
			androidsDamage(usRollA0ToNSidedDice(HULL_DAMAGE_ANDROIDS_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_CREW_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_CREW_CHANCE))
		{
			crewDamage(usRollA0ToNSidedDice(HULL_DAMAGE_CREW_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_MINING_DEVICES_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_MINING_DEVICES_CHANCE))
		{
			miningDevicesDamage(usRollA0ToNSidedDice(HULL_DAMAGE_MINING_DEVICES_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_SENSORS_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_SENSORS_CHANCE))
		{
			sensorsDamage(usRollA0ToNSidedDice(HULL_DAMAGE_SENSORS_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_PROBES_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_PROBES_CHANCE))
		{
			probesDamage(usRollA0ToNSidedDice(HULL_DAMAGE_PROBES_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_OTHER_EQUIPMENT_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_OTHER_EQUIPMENT_CHANCE))
		{
			otherEquipmentDamage(usRollA0ToNSidedDice(HULL_DAMAGE_OTHER_EQUIPMENT_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_CLOAKING_DEVICE_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_CLOAKING_DEVICE_CHANCE))
		{
			cloakingDeviceDamage(usRollA0ToNSidedDice(HULL_DAMAGE_CLOAKING_DEVICE_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_PAYLOAD_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_PAYLOAD_CHANCE))
		{
			payloadDamage(usRollA0ToNSidedDice(HULL_DAMAGE_PAYLOAD_SIGNIFICANCE));
		}
	}
	shipsAndBasesDamage(damagePerc, actualStructuralIntegrityPerc, annihilated);
	if (annihilated)
	{
		return damagePerc;
	}
	// predmety ve skladech se poskozuji jinak, protoze se musi projit cyklem a to by mohlo znacit kvadratickou zavislost
	for (dtIdentifierList::iterator litp1 = this->warehouse.storageBegin(); litp1 != this->warehouse.storageEnd(); litp1++)
	{
		actx->cacheItemsList.getItem<commonItemClass>(*litp1)->harm(usRollA0ToNSidedDice(2 * damagePerc)); // nasobi se dvema, protoze stredni hodnota je pak damageShardPerc
	}

	this->globalUpdate();

	return damagePerc;
}

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

unsigned long fortressClass::shieldsDeflection(unsigned long energyFromWeaponDamage, bool disruptiveBreakdown)
{
	unsigned long deflectionEnergy = (unsigned long)(this->deflectorShields.deflectorShieldsEnergyState.energy);
    unsigned long energyPassedByShields;

	if (energyFromWeaponDamage > deflectionEnergy)
	{
		energyPassedByShields  = energyFromWeaponDamage - deflectionEnergy;
		deflectionEnergy       = 0;
	}
	else
	{
		energyPassedByShields  = 0;
		deflectionEnergy      -= energyFromWeaponDamage;
	}

	if (disruptiveBreakdown)
	{
		energyPassedByShields  = energyFromWeaponDamage;
	}

	this->deflectorShields.deflectorShieldsEnergyState.energy = deflectionEnergy;
	return energyPassedByShields;
}

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

bool fortressClass::disruptiveBreakdownRaw(double att, double def)
{
	if (0 >= att)
		return 0;
	if (0 >= def)
		return 1;

	double chance = att / (att + def);

	return rollADice(chance);
};

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

bool fortressClass::droneDisruptiveBreakdown(fortressClass * targetFortress)
{
	return 0;
};

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

bool fortressClass::laserDisruptiveBreakdown(fortressClass * targetFortress, dtIdentifier laserGunID)
{
	double att = actx->cacheItemsList.getItem<laserGunClass>(laserGunID)->actualForcibility();
	double def = targetFortress->deflectorShields.deflectorShieldsGenerator()->actualSolidity();

	if ((FT_BASE == targetFortress->getFortressType()) && (FT_SHIP == this->getFortressType()))
	{
		def *= LASER_BREAKDOWN_MULTIPLICATOR_FOR_BASES;
		return disruptiveBreakdownRaw(att, def);
	}

	def *= LASER_BREAKDOWN_SHIELDS_MULTIPLICATOR;
	return disruptiveBreakdownRaw(att, def);
};

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

bool fortressClass::tBeamDisruptiveBreakdown(fortressClass * targetFortress)
{
	double att = this->transportBeam.transportBeamGenerator()->actualForcibility();
	double def = targetFortress->deflectorShields.deflectorShieldsGenerator()->actualSolidity();

	if ((FT_BASE == targetFortress->getFortressType()) && (FT_SHIP == this->getFortressType()))
	{
		def *= TBEAM_BREAKDOWN_MULTIPLICATOR_FOR_BASES;
		return disruptiveBreakdownRaw(att, def);
	}

	def *= TBEAM_BREAKDOWN_SHIELDS_MULTIPLICATOR;
	return disruptiveBreakdownRaw(att, def);
};

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

bool fortressClass::attackHitRaw(double att, double def)
{
	if ((0 < att) && (0 < def))
	{
		double chance = att / (att + def);
		return rollADice(chance);
	}
	else
	{
		if (0 < (att + def))
		{
			if (0 < att)
			{
				return 1;
			}
			else
			{
				return 0;
			}
		}
		else
		{
			return rollADice(0.5f);
		}
	}
};

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

bool fortressClass::droneAttackHit(fortressClass * targetFortress)
{
	double att = this->getManoeuvrability() +
		         DRONE_PRECISION_MULTIPLICATOR * actx->cacheRealmsList.getItem<realmClass>(realmID_)->getScientificTree()->getRealScienceLevel(SCIENCE_ENTITY_DRONE_MISSILES, INDEX_DRONE_MISSILES_PRECISION);
	double def = targetFortress->getManoeuvrability();

	return attackHitRaw(att, def);
};

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

bool fortressClass::laserAttackHit(fortressClass * targetFortress)
{
	double att = this->getManoeuvrability() +
		         LASER_PRECISION_MULTIPLICATOR * actx->cacheRealmsList.getItem<realmClass>(realmID_)->getScientificTree()->getRealScienceLevel(SCIENCE_ENTITY_LASER_GUN, INDEX_LASER_GUN_PRECISION);
	double def = targetFortress->getManoeuvrability();

	return attackHitRaw(att, def);
};

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

bool fortressClass::tBeamAttackHit(fortressClass * targetFortress)
{
	double att = this->getManoeuvrability() +
		         TBEAM_PRECISION_MULTIPLICATOR * actx->cacheRealmsList.getItem<realmClass>(realmID_)->getScientificTree()->getRealScienceLevel(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR, INDEX_TRANSPORT_BEAM_GENERATOR_PRECISION);
	double def = targetFortress->getManoeuvrability();

	return attackHitRaw(att, def);
};

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

attackResult fortressClass::attackFortress(fortressClass * targetFortress, unsigned short attackType, unsigned long launcherPos)
{
	if (!targetFortress)
	{
		return AR_TARGET_ANNIHILATED;
	}

	targetFortress->currentAttackerTEMP_ = this;

	unsigned long attackPower = 0;
	switch (attackType)
	{
	case ATTACK_TYPE_DRONES:
		attackPower = fireDroneMissile(launcherPos);
		break;
	case ATTACK_TYPE_LASER:
		attackPower = fireLaser(launcherPos);
		break;
	case ATTACK_TYPE_TBEAM:
		attackPower = fireTBeam();
		break;
	}

	if (!(0 < attackPower))
	{
		targetFortress->currentAttackerTEMP_ = NULL;
		return AR_NOT_FIRED;
	}

	attackReportClass clientAttackReport(this, targetFortress, 1);

	bool hit = ((ATTACK_TYPE_DRONES == attackType) && (droneAttackHit(targetFortress))) ||
		       ((ATTACK_TYPE_LASER  == attackType) && (laserAttackHit(targetFortress))) ||
			   ((ATTACK_TYPE_TBEAM  == attackType) && (tBeamAttackHit(targetFortress)));
	if (!(hit))
	{
		targetFortress->currentAttackerTEMP_ = NULL;
		clientAttackReport.result = AR_MISS;
		return AR_MISS;
	}

	bool disruptiveBreakdown = ((ATTACK_TYPE_DRONES == attackType) && (droneDisruptiveBreakdown(targetFortress))                                                   ) ||
		                       ((ATTACK_TYPE_LASER  == attackType) && (laserDisruptiveBreakdown(targetFortress, this->weapons.laserGunsOnly(launcherPos)->getID()))) ||
							   ((ATTACK_TYPE_TBEAM  == attackType) && (tBeamDisruptiveBreakdown(targetFortress))                                                   );
	clientAttackReport.disruptiveBreakdown = disruptiveBreakdown;

	bool annihilated = 0;

	clientAttackReport.readInitialValues(targetFortress);
	unsigned long  energyPassedByShields   = targetFortress->shieldsDeflection(attackPower, disruptiveBreakdown);
	unsigned short structuralIntegrityLoss = targetFortress->hullDeflection(energyPassedByShields, annihilated);
	clientAttackReport.unreadFinalValues(targetFortress);
	if (annihilated)
	{
		clientAttackReport.targetAnnihilated();
	}

	if (0 < structuralIntegrityLoss)
	{
		if (50 > structuralIntegrityLoss)
		{
			if (!annihilated)
			{
				targetFortress->currentAttackerTEMP_ = NULL;
			}
			clientAttackReport.result = AR_HIT;
			return AR_HIT;
		}
		else
		{
			if (!annihilated)
			{
				targetFortress->currentAttackerTEMP_ = NULL;
			}
			clientAttackReport.result = AR_CRITICAL_HIT;
			return AR_CRITICAL_HIT;
		}
	}
	else
	{
		if (!annihilated)
		{
			targetFortress->currentAttackerTEMP_ = NULL;
		}
		clientAttackReport.result = AR_FUTILE_HIT;
		return AR_FUTILE_HIT;
	}
};

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

unsigned long long fortressClass::getBuildingAndroidsCountForHangar(dtIdentifier hangarID)
{
	if (FT_BASE != this->getFortressType())
	{
		return 0;
	}
	baseClass * constructingBase = (baseClass *)this;
	vector<unsigned long long> droidsInHangars;
	droidsInHangars.resize(constructingBase->hangarsPort.getHangarsCount(), 0);
	stacksAndLimits piles;
	unsigned long hangarPosition = (unsigned long)droidsInHangars.size();
	unsigned long loop1          = 0;
	for (dtIdentifierDeque::const_iterator litp1 = constructingBase->hangarsPort.beginHangarsIdentifiers(); litp1 != constructingBase->hangarsPort.endHangarsIdentifiers(); litp1++)
	{		
		if (hangarID == (*litp1))
		{
			hangarPosition = loop1;
		}
		hangarClass * actualHangar = constructingBase->hangarsPort.hangarByIdentifier(*(litp1));
		piles.push_back(make_pair(&(droidsInHangars[loop1]), constructingBase->hangarsPort.getMaxRepairingMechanicsBySize(actualHangar->getCreationsSize()) * actualHangar->getCreationsCount()));
		loop1++;
	}
	divideIntoPiles(this->mechanics.getActualConstructingAndroids(), piles);
	if (hangarPosition < droidsInHangars.size())
	{
		return droidsInHangars[hangarPosition];
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isSomethingQuarrying()
{
    return 
        miningDevices.isActuallyHeavyWaterQuarrying() ||
        miningDevices.isActuallyQuarkGluonPlasmaQuarrying() ||
        miningDevices.isActuallyIlmeniteQuarrying() ||
        miningDevices.isActuallyZirconiumCrystalQuarrying();
}

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

double fortressClass::startQuarryQuarkGluonPlasma()
{
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	double speed = 0;
	if (this->isPossibleToQuarryQuarkGluonPlasma(NULL))
	{
		speed = this->miningDevices.startQuarkGluonPlasmaQuarrying(this->getFortressRealmID());
	}
	else
	{
		this->miningDevices.finishQuarkGluonPlasmaQuarrying();
	}
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	return speed;
}

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

double fortressClass::startQuarryHeavyWater()
{
	this->containeredResourcesUpdate();
	double modifier = this->heavyWaterActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	double speed    = this->miningDevices.startHeavyWaterQuarrying(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	return speed;
}

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

double fortressClass::startQuarryZirconiumCrystal()
{
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
	double modifier = this->zirconiumCrystalActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	double speed    = this->miningDevices.startZirconiumCrystalQuarrying(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
	return speed;
}

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

double fortressClass::startQuarryIlmenite()
{
	this->containeredResourcesUpdate();
	double modifier = this->ilmeniteActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	double speed    = this->miningDevices.startIlmeniteQuarrying(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	return speed;
}

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

void fortressClass::stopQuarryQuarkGluonPlasma()
{
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
	this->miningDevices.finishQuarkGluonPlasmaQuarrying();
	this->quarkGluonPlasmaUpdate();
	this->ulreaUpdate();
}

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

void fortressClass::stopQuarryHeavyWater()
{
	this->containeredResourcesUpdate();
	this->miningDevices.finishHeavyWaterQuarrying();
	this->containeredResourcesUpdate();
}

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

void fortressClass::stopQuarryZirconiumCrystal()
{
	this->containeredResourcesUpdate();
	this->miningDevices.finishZirconiumCrystalQuarrying();
	this->containeredResourcesUpdate();
}

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

void fortressClass::stopQuarryIlmenite()
{
	this->containeredResourcesUpdate();
	this->miningDevices.finishIlmeniteQuarrying();
	this->containeredResourcesUpdate();
}

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

void fortressClass::stopAllQuarrying()
{
	this->resourcesUpdate();
	this->miningDevices.finishAllQuarrying();
	this->resourcesUpdate();
}

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

void fortressClass::stopAllQuarryingIfQuarryingSomething()
{
    if (miningDevices.isActuallyQuarkGluonPlasmaQuarrying() ||
        miningDevices.isActuallyHeavyWaterQuarrying() ||
        miningDevices.isActuallyZirconiumCrystalQuarrying() ||
        miningDevices.isActuallyIlmeniteQuarrying() )
    {
        stopAllQuarrying();
    }
}

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

/*unsigned long fortressClass::rawMaterialContainersTransferLimit(unsigned long      containers,
																unsigned long long targetFreeWeight,
																unsigned long long targetFreeCapacity,
																unsigned long long totalMaterialWeight,
																unsigned long long totalMaterialSize, 
																unsigned long      materialDensity,
																unsigned long long otherRawMaterialsCapacity,
																unsigned long      totalSourceContainers, 
																unsigned long      workingSourceContainers,
																unsigned long      containerWeight,
																unsigned long      containerSize,
																unsigned long      containerCapacity)
{
	if (0 == containerCapacity)
	{
		return 0;
	}
	unsigned long containersForOtherRawMaterials = (unsigned long)ullUpRoundDiv(otherRawMaterialsCapacity, (unsigned long long)containerCapacity);

	containers =                min(containers, workingSourceContainers);
	containers = (unsigned long)min((unsigned long long)containers, (unsigned long long)ullUpRoundDiv(totalMaterialSize, containerCapacity));
	containers =                min(containers, totalSourceContainers - containersForOtherRawMaterials);


	unsigned long long transferedMaterialWeight   = min(totalMaterialWeight, (unsigned long long)containers * (unsigned long long)containerCapacity * (unsigned long long)materialDensity);
	unsigned long long transferedContainersWeight = (unsigned long long)containers * (unsigned long long)containerWeight;
	unsigned long long transferedTotalWeight      = transferedMaterialWeight + transferedContainersWeight;

	if (targetFreeWeight < transferedTotalWeight) // cilova lod to neunese
	{
		unsigned long long fullContainerWeight = (unsigned long long)containerWeight + 
			                                     (unsigned long long)containerCapacity * (unsigned long long)materialDensity;
		if (0 == fullContainerWeight)
		{
			return 0;
		}
		containers = (unsigned long)min((unsigned long long)containers, (unsigned long long)targetFreeWeight / (unsigned long long)fullContainerWeight);
	}


	unsigned long long transferedContainersSize = (unsigned long long)containers * (unsigned long long)containerSize;
	
	if (targetFreeCapacity < transferedContainersSize) // nevejde se to tam
	{
		if (0 == containerSize)
		{
			return 0;
		}
		containers = (unsigned long)min((unsigned long long)containers, (unsigned long long)targetFreeCapacity / (unsigned long long)containerSize);
	}


	return containers;
};*/

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

unsigned long long fortressClass::fortressCoreOnlyCargoWeight(bool doNotUpdate, bool ignoreResources, bool softUpdate)
{
	unsigned long long result = 0;

	if (!ignoreResources)
	{
		if (doNotUpdate)
		{
			result += ullUpRound(heavyWater_);
			result += ullUpRound(deuterium_);
			result += ullUpRound(zirconiumCrystal_);
			result += ullUpRound(ilmenite_);
			result += ullUpRound(titanium_);
		}
		else
		{
			result += containeredResourcesInKg(softUpdate);
		}
	}

	result += energeticSystem.getEnergeticSystemWeight();
	result += deflectorShields.getDeflectorShieldsWeight();
	result += weapons.getWeaponsWeight();
	result += transportBeam.getTransportBeamWeight();
	result += miningDevices.getMiningDevicesWeight();
	result += probeDevices.getProbeDevicesWeight();
	result += sensors.getSensorsWeight();
	result += cloaking.getCloakingWeight();
	result += crew.getCrewWeight();
	result += accommodations.getAccomodationsWeight();
	result += mechanics.getMechanicsWeight();
	result += warehouse.getWarehouseWeight();
	result += otherEquipment.getOtherEquipmentWeight();
	result += mainframeSystem.getMainframeSystemWeight();

	return result;
};

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

unsigned long long fortressClass::fortressCoreOnlySizeOfCargoInWarehouse()
{
	unsigned long long result = 0;

	result += weapons.getDroneMissilesSize();
	result += miningDevices.getMiningDevicesSize();
	result += probeDevices.getProbeDevicesSize();
	result += mechanics.getMechanicsSize();
	result += warehouse.getSizeOfItemsInWarehouse();

	return result;
};

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

double fortressClass::quarkGluonPlasmaQuarryingPotential()
{
	return this->miningDevices.getQuarkGluonPlasmaQuarrying();
}

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

double fortressClass::heavyWaterQuarryingPotential()
{
	return this->miningDevices.getHeavyWaterQuarrying();
}

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

double fortressClass::zirconiumCrystalQuarryingPotential()
{
	return this->miningDevices.getZirconiumCrystalQuarrying();
}

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

double fortressClass::ilmeniteQuarryingPotential()
{
	return this->miningDevices.getIlmeniteQuarrying();
}

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

double fortressClass::quarkGluonPlasmaQuarryingSpeed()
{
	unsigned long long freeSpace = freeSpaceForQuarkGluonPlasmaInMiligrams(1, 0);
	double             rawSpeed  = quarkGluonPlasmaQuarryingPotential();
	if (rawSpeed < freeSpace)
	{
		return rawSpeed;
	}
	else
	{
		double potentialConsumption = quarkGluonPlasmaConsumptionPotential();
		return min(rawSpeed, potentialConsumption + (double)freeSpace);
	}
}

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

double fortressClass::quarkGluonPlasmaConsumptionSpeed()
{
	double QGPSupplies = quarkGluonPlasma_;
	double rawSpeed    = quarkGluonPlasmaConsumptionPotential();
	if (rawSpeed < QGPSupplies)
	{
		return rawSpeed;
	}
	else
	{
		double quarrying = quarkGluonPlasmaQuarryingSpeed();
		return min(rawSpeed, quarrying + QGPSupplies);
	}
}

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

double fortressClass::deuteriumFabricationSpeed(dv_time::datetime * nextChange)
{
	double realIncome = heavyWaterQuarryingSpeed();
	double realSupply = heavyWater_;
	double realProduction = (double)deuteriumProductionByConsumption((unsigned long long)realIncome + (unsigned long long)realSupply);
	if ((0 < realProduction) && (NULL != nextChange))
	{
		double potentialConsumption = heavyWaterConsumptionPotential();
		double potentialProduction  = (double)deuteriumProductionByConsumption((unsigned long long)potentialConsumption);
		if (realIncome < potentialConsumption)
		{
			double supplyPotentialConsumption = potentialConsumption - realIncome;
			if (realSupply < supplyPotentialConsumption)
			{
				if (0 < realSupply)
				{
					(*nextChange) = wt2gt(dv_time::now()) + dv_time::encodeSeconds(1);
				}
				// else nextChance zustava
			}
			else
			{
				unsigned long long secondsToChange = (unsigned long long)(realSupply / supplyPotentialConsumption);
				dv_time::datetime  potentialChange = wt2gt(dv_time::now()) + dv_time::encodeSeconds(secondsToChange);
				(*nextChange) = min((*nextChange), potentialChange);
			}
		}
	}
	return realProduction;
}

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

double fortressClass::deuteriumConsumptionSpeed()
{
	return impulsJetEngineConsumption();
}

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

double fortressClass::energyHarvestingSpeed(dv_time::datetime * nextChange)
{
	double realIncome = zirconiumCrystalQuarryingSpeed();
	double realSupply = zirconiumCrystal_;
	double realProduction = energyProductionByConsumption(realIncome + realSupply);
	if ((0 < realProduction) && (NULL != nextChange))
	{
		double potentialConsumption = zirconiumCrystalConsumptionPotential();
		double potentialProduction  = energyProductionByConsumption(potentialConsumption);
		if (realIncome < potentialConsumption)
		{
			double supplyPotentialConsumption = potentialConsumption - realIncome;
			if (supplyPotentialConsumption > realSupply)
			{
				(*nextChange) = wt2gt(dv_time::now()) + dv_time::encodeSeconds(1);
			}
			else
			{
				unsigned long long secondsToChange = (unsigned long long)(realSupply / supplyPotentialConsumption);
				dv_time::datetime  potentialChange = wt2gt(dv_time::now()) + dv_time::encodeSeconds(secondsToChange);
				(*nextChange) = min((*nextChange), potentialChange);
			}
		}
	}
	return realProduction;
}

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

double fortressClass::titaniumFabricationSpeed(dv_time::datetime * nextChange)
{
	double realIncome = ilmeniteQuarryingSpeed();
	double realSupply = ilmenite_;
	double realProduction = (double)titaniumProductionByConsumption((unsigned long long)realIncome + (unsigned long long)realSupply);
	if ((0 < realProduction) && (NULL != nextChange))
	{
		double potentialConsumption = ilmeniteConsumptionPotential();
		double potentialProduction  = (double)titaniumProductionByConsumption((unsigned long long)potentialConsumption);
		if (realIncome < potentialConsumption)
		{
			double supplyPotentialConsumption = potentialConsumption - realIncome;
			if (realSupply < supplyPotentialConsumption)
			{
				if (0 < realSupply)
				{
					(*nextChange) = wt2gt(dv_time::now()) + dv_time::encodeSeconds(1);
				}
				// else nechame nextChange
			}
			else
			{
				unsigned long long secondsToChange = (unsigned long long)(realSupply / supplyPotentialConsumption);
				dv_time::datetime  potentialChange = wt2gt(dv_time::now()) + dv_time::encodeSeconds(secondsToChange);
				(*nextChange) = min((*nextChange), potentialChange);
			}
		}
	}
	return realProduction;
}

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

unsigned long long fortressClass::mountingPointsRequiredForItemMounting(commonItemClass * item, unsigned long long count)
{
	return (unsigned long long)item->getWeight() * min((unsigned long long)count, (unsigned long long)item->getCount()) * (unsigned long long)item->getMounting();
};

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

unsigned long long fortressClass::energyRequiredForItemMounting(unsigned long long mountingPointsRequired)
{
	if (0 == ((unsigned long long)this->mechanics.androids()->actualPointsPerSecond(this)))
	{
		return 0;
	}
	unsigned long long androidSecondsRequired = mountingPointsRequired / (unsigned long long)this->mechanics.androids()->actualPointsPerSecond(this                      );
	return                                      androidSecondsRequired * (unsigned long long)this->mechanics.androids()->actualConsumption    (this->getFortressRealmID());
};

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

mountingResult fortressClass::mountStoragedItem(dtIdentifierList::iterator warehouseItem, unsigned long long workingCount)
{
	commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*warehouseItem);
	if (item->isStackable())
	{
		workingCount       = min(workingCount, ((stackableItemClass *)(item))->getWorking());
	}
	else
	{
		workingCount       = min(workingCount, (unsigned long long)1);
	}

	unsigned long long mountingPointsRequired = this->mountingPointsRequiredForItemMounting(item, workingCount);

	if ((0 == this->mechanics.androids()->getWorking()     ) &&
		(0 == this->crew.getEffectiveCountOf(CREW_ENGINEER)) &&
		(0 < mountingPointsRequired                        ))
	{
		return MR_NOT_ENOUGH_ANDROIDS;
	}

	unsigned long long energyRequired         = this->energyRequiredForItemMounting(mountingPointsRequired);
	if (this->energyInTJ(1) < energyRequired)
	{
		return MR_NOT_ENOUGH_ENERGY;
	}
	
	bool mountingResult = 0;
	bool someItemBack   = 0;
	
	if (NOT_VALID_ID == item->getPatternID())
	{
		errLogicalError("Null item (ID %u) in fortress (ID %u) storage.", (unsigned long long)item->getID(), (unsigned long long)this->getID());
		return MR_UNKNOWN_FAIL;
	}

	switch (item->getPatternID())
	{
	case PATTERN_ID_ENERGETIC_ACCUMULATOR:
		if ((item->getSize() < this->energeticSystem.energeticAccumulator()->getSize()) &&
			(this->freeCapacity() < (this->energeticSystem.energeticAccumulator()->getSize() - item->getSize())))
		{
			return MR_NOT_ENOUGH_STORAGE_SPACE;
		}
		(*warehouseItem) = this->changeEnergeticAccumulator(item->getID());
		mountingResult = 1;
		someItemBack   = 1;
		break;
	case PATTERN_ID_MAINFRAME:
		if ((item->getSize() < this->mainframeSystem.mainframe()->getSize()) &&
			(this->freeCapacity() < (this->mainframeSystem.mainframe()->getSize() - item->getSize())))
		{
			return MR_NOT_ENOUGH_STORAGE_SPACE;
		}
		(*warehouseItem) = this->changeMainframe(item->getID());
		mountingResult = 1;
		someItemBack   = 1;
		break;
	case PATTERN_ID_QUARK_GLUON_CORE:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountQuarkGluonPlasmaCore(item->getID());
		break;
	case PATTERN_ID_NAVIGATION_COMPUTER:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountNavigationComputer(item->getID());
		break;
	case PATTERN_ID_SUBSPACE_BEACON:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountSubspaceBeacon(item->getID());
		break;
	case PATTERN_ID_INERTIAL_DAMPERS:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountInertialDampers(item->getID());
		break;
	case PATTERN_ID_IMPULS_JET_ENGINE:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountImpulsJetEngine(item->getID());
		break;
	case PATTERN_ID_MECHANICAL_DAMPERS:
		if (FT_SHIP != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountMechanicalDampers(item->getID());
		break;
	case PATTERN_ID_DEFLECTOR_SHIELDS:
		mountingResult = this->mountDeflectorShieldsGenerator(item->getID());
		break;
	case PATTERN_ID_WEAPON_ENERGY_CIRCUIT:
		mountingResult = this->mountWeaponEnergyCircuit(item->getID());
		break;
	case PATTERN_ID_DRONE_MISSILES:
		mountingResult = this->mountDroneMissiles((droneMissilesClass *)item, workingCount);
		break;
	case PATTERN_ID_DRONE_MISSILE_LAUNCHER:
		mountingResult = this->mountDroneMissileLauncher(item->getID());
		break;
	case PATTERN_ID_LASER_GUN:
		mountingResult = this->mountLaserGun(item->getID());
		break;
	case PATTERN_ID_TRANSPORT_BEAM_GENERATOR:
		mountingResult = this->mountTransportBeamGenerator(item->getID());
		break;
	case PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA:
		mountingResult = this->mountMagneticalCollectorsOfPlasma((magneticalCollectorsOfPlasmaClass *)item, workingCount);
		break;
	case PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK:
		mountingResult = this->mountSubmersibleFiltrationTanks((submersibleFiltrationTankClass *)item, workingCount);
		break;
	case PATTERN_ID_SUBMARINE_MINING_MACHINE:
		mountingResult = this->mountSubmarineMiningMachines((submarineMiningMachineClass *)item, workingCount);
		break;
	case PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE:
		mountingResult = this->mountUndergroundDrillingMachines((undergroundDrillingMachineClass *)item, workingCount);
		break;
	case PATTERN_ID_PROBE:
		mountingResult = this->mountProbe(item->getID());
		break;
	case PATTERN_ID_HIGH_RESOLUTION_SENSORS:
		mountingResult = this->mountHighResolutionSensors(item->getID());
		break;
	case PATTERN_ID_LONG_RANGE_SENSORS:
		mountingResult = this->mountLongRangeSensors(item->getID());
		break;
	case PATTERN_ID_CLOAKING_DEVICE:
		mountingResult = this->mountCloakingDevice(item->getID());
		break;
	case PATTERN_ID_ANDROIDS:
		mountingResult = this->mountAndroids((androidsClass *)item, workingCount);
		break;
	case PATTERN_ID_PLASMA_FILTER:
		mountingResult = this->mountPlasmaFilter(item->getID());
		break;
	case PATTERN_ID_SCIENTIFIC_LAB:
		mountingResult = this->mountScientificLab(item->getID());
		break;
	case PATTERN_ID_LIFE_SUPPORT:
		mountingResult = this->mountLifeSupport(item->getID());
		break;
	case PATTERN_ID_SUBSPACE_TRANSMITTER:
		mountingResult = this->mountSubspaceTransmitter(item->getID());
		break;
	case PATTERN_ID_HANGAR:
		if (FT_BASE != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountHangar(item->getID());
		break;
	case PATTERN_ID_MAGNETICAL_FILTER:
		if (FT_BASE != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountMagneticalFilter((magneticalFilterClass *)item, workingCount);
		break;
	case PATTERN_ID_DEUTERIUM_DECOMPOSER:
		if (FT_BASE != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountDeuteriumDecomposer((deuteriumDecomposerClass *)item, workingCount);
		break;
	case PATTERN_ID_ZIRCONIUM_REACTOR:
		if (FT_BASE != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountZirconiumReactor((zirconiumReactorClass *)item, workingCount);
		break;
	case PATTERN_ID_ILMENITE_FURNACE:
		if (FT_BASE != this->getFortressType())
		{
			return MR_BAD_FORTRESS_TYPE;
		}
		mountingResult = this->mountIlmeniteFurnace((ilmeniteFurnaceClass *)item, workingCount);
		break;
	}

	if (mountingResult)
	{
		if (item->isStackable())
		{
			stackableItemClass * stackableItem = (stackableItemClass *)item;
			if (someItemBack)
			{
				errLogicalError("Stackable item returned back while mounted.");
			}
			this->warehouse.dropItem(warehouseItem, workingCount, 0, 1);
		}
		else
		{
			if (!(someItemBack))
			{
				this->warehouse.dropItem(warehouseItem, 0);
			}
		}
		this->subEnergy(energyRequired);
		return MR_DONE;
	}
	else
	{
		return MR_SLOT_OCCUPIED;
	}

	return MR_UNKNOWN_FAIL;
};

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

mountingResult fortressClass::mountStoragedItem(dtIdentifierList::iterator warehouseItem)
{
	return this->mountStoragedItem(warehouseItem, 1);
};

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

dtIdentifier fortressClass::changeEnergeticAccumulator(dtIdentifier newEAID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	dtIdentifier oldEAID = this->energeticSystem.changeEnergeticAccumulator(newEAID);
	this->energyDistributionPhaseAndWeaponsFire();
	return oldEAID;
};

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

dtIdentifier fortressClass::changeMainframe(dtIdentifier newMFID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	if (FT_SHIP == this->getFortressType())
	{
		((shipClass *)(this))->MovementUpdateShipMovementStatus();
	}
	dtIdentifier oldMFID = this->mainframeSystem.changeMainframe(newMFID);
	if (NOT_VALID_ID == newMFID)
	{
		this->getFortressRealm()->mainframeFailure(this);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	if (FT_SHIP == this->getFortressType())
	{
		((shipClass *)(this))->MovementUpdateShipMovementStatus();
	}
	return oldMFID;
};

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

bool shipClass::mountQuarkGluonPlasmaCore(dtIdentifier newQGPC)
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->subspaceDrive.mountQuarkGluonCore(newQGPC);
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

bool shipClass::mountNavigationComputer(dtIdentifier newNC)
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->subspaceDrive.mountNavigationComputer(newNC);
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

bool shipClass::mountSubspaceBeacon(dtIdentifier newSB)
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->subspaceDrive.mountSubspaceBeacon(newSB);
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

bool shipClass::mountInertialDampers(dtIdentifier newID)
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->subspaceDrive.mountInertialDampers(newID);
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

bool shipClass::mountImpulsJetEngine(dtIdentifier newIJE)
{
	this->containeredResourcesUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->impulsDrive.mountImpulsJetEngine(newIJE);
	this->MovementUpdateShipMovementStatus();
	this->containeredResourcesUpdate();
	return result;
};

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

bool shipClass::mountMechanicalDampers(dtIdentifier newMD)
{
	this->containeredResourcesUpdate();
	this->MovementUpdateShipMovementStatus();
	bool result = this->impulsDrive.mountMechanicalDampers(newMD);
	this->MovementUpdateShipMovementStatus();
	this->containeredResourcesUpdate();
	return result;
};

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

bool fortressClass::mountDeflectorShieldsGenerator(dtIdentifier newDSGID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->deflectorShields.mountDeflectorShieldsGenerator(newDSGID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountWeaponEnergyCircuit(dtIdentifier newWECID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->weapons.mountWeaponEnergyCircuit(newWECID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountDroneMissiles(droneMissilesClass * pattern, unsigned long long count)
{
	this->weapons.mountDroneMissiles(pattern, count);
	return 1;
};

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

bool fortressClass::mountDroneMissileLauncher(dtIdentifier newDMLID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->weapons.mountDroneMissileLauncher(this, newDMLID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountLaserGun(dtIdentifier newLGID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result  = this->weapons.mountLaserGun(this, newLGID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountTransportBeamGenerator(dtIdentifier newTBGID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->transportBeam.mountTransportBeamGenerator(newTBGID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountMagneticalCollectorsOfPlasma(magneticalCollectorsOfPlasmaClass * pattern, unsigned long long count)
{
	this->quarkGluonPlasmaUpdate();
	this->miningDevices.mountMagneticalCollectorsOfPlasma(pattern, count);
	this->miningDevices.quarkGluonPlasmaDeviceChange(this->getFortressRealmID());
	this->quarkGluonPlasmaUpdate();
	return 1;
};


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

bool fortressClass::mountSubmersibleFiltrationTanks(submersibleFiltrationTankClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->miningDevices.mountSubmersibleFiltrationTanks(pattern, count);
	double modifier = this->heavyWaterActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	this->miningDevices.heavyWaterDeviceChange(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	return 1;
};

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

bool fortressClass::mountSubmarineMiningMachines(submarineMiningMachineClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->miningDevices.mountSubmarineMiningMachines(pattern, count);
	double modifier = this->zirconiumCrystalActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	this->miningDevices.zirconiumCrystalDeviceChange(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	return 1;
};

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

bool fortressClass::mountUndergroundDrillingMachines(undergroundDrillingMachineClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->miningDevices.mountUndergroundDrillingMachines(pattern, count);
	double modifier = this->ilmeniteActualModifier() * this->getFortressQuarryingModifierMultiplicator();
	this->miningDevices.ilmeniteDeviceChange(this->getFortressRealmID(), modifier);
	this->containeredResourcesUpdate();
	return 1;
};

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

bool fortressClass::mountProbe(dtIdentifier newPID)
{
	return this->probeDevices.mountProbe(newPID);
};

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

bool fortressClass::mountHighResolutionSensors(dtIdentifier newHRSID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->sensors.mountHighResolutionSensors(newHRSID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountLongRangeSensors(dtIdentifier newLRSID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->sensors.mountLongRangeSensors(newLRSID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountCloakingDevice(dtIdentifier newCDID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->cloaking.mountCloakingDevice(newCDID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountAndroids(androidsClass * pattern, unsigned long long count)
{
	this->energyDistributionPhaseAndWeaponsFire();
	this->mechanics.mountAndroids(pattern, count);
	this->energyDistributionPhaseAndWeaponsFire();
	return 1;
};

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

bool fortressClass::mountPlasmaFilter(dtIdentifier newPFID)
{
	this->quarkGluonPlasmaUpdate();
	bool result = this->otherEquipment.mountPlasmaFilter(newPFID);
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

bool fortressClass::mountScientificLab(dtIdentifier newSLID)
{
	return this->otherEquipment.mountScientificLab(newSLID);
};

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

bool fortressClass::mountLifeSupport(dtIdentifier newLSID)
{
	this->energyDistributionPhaseAndWeaponsFire();
	bool result = this->otherEquipment.mountLifeSupport(newLSID);
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

bool fortressClass::mountSubspaceTransmitter(dtIdentifier newSTID)
{
	return this->otherEquipment.mountSubspaceTransmitter(newSTID);
};

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

bool baseClass::mountHangar(dtIdentifier newH)
{
	return this->hangarsPort.mountHangar(newH);
};

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

bool baseClass::mountMagneticalFilter(magneticalFilterClass * pattern, unsigned long long count)
{
	this->quarkGluonPlasmaUpdate();
	this->factories.mountMagneticalFilters(pattern, count);
	this->quarkGluonPlasmaUpdate();
	return 1;
};

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

bool baseClass::mountDeuteriumDecomposer(deuteriumDecomposerClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->factories.mountDeuteriumDecomposers(pattern, count);
	this->containeredResourcesUpdate();
	return 1;
};

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

bool baseClass::mountZirconiumReactor(zirconiumReactorClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
	this->factories.mountZirconiumReactors(pattern, count);
	this->energyDistributionPhaseAndWeaponsFire();
	this->containeredResourcesUpdate();
	return 1;
};

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

bool baseClass::mountIlmeniteFurnace(ilmeniteFurnaceClass * pattern, unsigned long long count)
{
	this->containeredResourcesUpdate();
	this->factories.mountIlmeniteFurnaces(pattern, count);
	this->containeredResourcesUpdate();
	return 1;
};

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

mountingResult shipClass::unmountQuarkGluonCore()
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->subspaceDrive.quarkGluonCore(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->subspaceDrive.unmountQuarkGluonCore(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult shipClass::unmountNavigationComputer()
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->subspaceDrive.navigationComputer(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->subspaceDrive.unmountNavigationComputer(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult shipClass::unmountSubspaceBeacon()
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->subspaceDrive.subspaceBeacon(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->subspaceDrive.unmountSubspaceBeacon(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult shipClass::unmountInertialDampers()
{
	this->quarkGluonPlasmaUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->subspaceDrive.inertialDampers(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->subspaceDrive.unmountInertialDampers(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult shipClass::unmountImpulsJetEngine()
{
	this->containeredResourcesUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->impulsDrive.impulsJetEngine(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->impulsDrive.unmountImpulsJetEngine(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult shipClass::unmountMechanicalDampers()
{
	this->containeredResourcesUpdate();
	this->MovementUpdateShipMovementStatus();
	mountingResult result = this->unmountItemPrepare(this->impulsDrive.mechanicalDampers(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->impulsDrive.unmountMechanicalDampers(), 0);
	}
	this->MovementUpdateShipMovementStatus();
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult fortressClass::unmountDeflectorShieldsGenerator()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->deflectorShields.deflectorShieldsGenerator(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->deflectorShields.unmountDeflectorShieldsGenerator(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountWeaponEnergyCircuit()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->weapons.weaponEnergyCircuit(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->weapons.unmountWeaponEnergyCircuit(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountDroneMissiles(unsigned long long & working, unsigned long long & damaged)
{
	mountingResult result = this->unmountItemPrepare(this->weapons.droneMissiles(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->weapons.droneMissiles()->subWorking(working);
		damaged = this->weapons.droneMissiles()->subDamaged(damaged);
		this->warehouse.addItem(this->weapons.droneMissiles(), working, damaged, 0);
	}
	return result;
};

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

mountingResult fortressClass::unmountDroneMissileLauncher(dtIdentifier DMLID)
{
	if (NOT_VALID_ID == DMLID)
	{
		return MR_SLOT_EMPTY;
	}
	commonItemClass * dml = actx->cacheItemsList.getItem<commonItemClass>(DMLID);
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(dml, 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->weapons.unmountDroneMissileLauncherByID(DMLID), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountLaserGun(dtIdentifier LGID)
{
	if (NOT_VALID_ID == LGID)
	{
		return MR_SLOT_EMPTY;
	}
	commonItemClass * lg = actx->cacheItemsList.getItem<commonItemClass>(LGID);
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(lg, 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->weapons.unmountLaserGubByID(LGID), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountTransportBeamGenerator()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->transportBeam.transportBeamGenerator(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->transportBeam.unmountTransportBeamGenerator(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountMagneticalCollectorsOfPlasma(unsigned long long &working, unsigned long long &damaged)
{
	this->quarkGluonPlasmaUpdate();
	mountingResult result = this->unmountItemPrepare(this->miningDevices.magneticalCollectorsOfPlasma(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->miningDevices.magneticalCollectorsOfPlasma()->subWorking(working);
		damaged = this->miningDevices.magneticalCollectorsOfPlasma()->subDamaged(damaged);
		this->warehouse.addItem(this->miningDevices.magneticalCollectorsOfPlasma(), working, damaged, 0);
	}
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult fortressClass::unmountSubmersibleFiltrationTanks(unsigned long long &working, unsigned long long &damaged)
{
	this->containeredResourcesUpdate();
	mountingResult result = this->unmountItemPrepare(this->miningDevices.submersibleFiltrationTank(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->miningDevices.submersibleFiltrationTank()->subWorking(working);
		damaged = this->miningDevices.submersibleFiltrationTank()->subDamaged(damaged);
		this->warehouse.addItem(this->miningDevices.submersibleFiltrationTank(), working, damaged, 0);
	}
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult fortressClass::unmountSubmarineMiningMachines(unsigned long long &working, unsigned long long &damaged)
{
	this->containeredResourcesUpdate();
	mountingResult result = this->unmountItemPrepare(this->miningDevices.submarineMiningMachine(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->miningDevices.submarineMiningMachine()->subWorking(working);
		damaged = this->miningDevices.submarineMiningMachine()->subDamaged(damaged);
		this->warehouse.addItem(this->miningDevices.submarineMiningMachine(), working, damaged, 0);
	}
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult fortressClass::unmountUndergroundDrillingMachines(unsigned long long &working, unsigned long long &damaged)
{
	this->containeredResourcesUpdate();
	mountingResult result = this->unmountItemPrepare(this->miningDevices.undergroundDrillingMachine(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->miningDevices.undergroundDrillingMachine()->subWorking(working);
		damaged = this->miningDevices.undergroundDrillingMachine()->subDamaged(damaged);
		this->warehouse.addItem(this->miningDevices.undergroundDrillingMachine(), working, damaged, 0);
	}
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult fortressClass::unmountProbe(dtIdentifier PID)
{
	if (NOT_VALID_ID == PID)
	{
		return MR_SLOT_EMPTY;
	}
	commonItemClass * pro = actx->cacheItemsList.getItem<commonItemClass>(PID);
	mountingResult result = this->unmountItemPrepare(pro, 1);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->probeDevices.unmountProbeByID(PID), 0);
	}
	return result;
};

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

mountingResult fortressClass::unmountHighResolutionSensors()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->sensors.highResolutionSensors(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->sensors.unmountHighResolutionSensors(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountLongRangeSensors()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->sensors.longRangeSensors(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->sensors.unmountLongRangeSensors(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountCloakingDevice()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->cloaking.cloakingDevice(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->cloaking.unmountCloakingDevice(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountAndroids(unsigned long long &working, unsigned long long &damaged)
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->mechanics.androids(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->mechanics.androids()->subWorking(working);
		damaged = this->mechanics.androids()->subDamaged(damaged);
		this->warehouse.addItem(this->mechanics.androids(), working, damaged, 0);
	}
	this->mechanics.androidsEnergyDivision.maxPowerDrain = max((double)0, min(this->mechanics.androidsEnergyDivision.maxPowerDrain, this->mechanics.androids()->maxPossibleConsumption()));
	this->mechanics.setMaxWorkingAndroids  (this->mechanics.getMaxWorkingAndroidsSoft  ());
	this->mechanics.setMaxRepairingAndroids(this->mechanics.getMaxRepairingAndroidsSoft());
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountPlasmaFilter()
{
	this->quarkGluonPlasmaUpdate();
	mountingResult result = this->unmountItemPrepare(this->otherEquipment.plasmaFilter(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->otherEquipment.unmountPlasmaFilter(), 0);
	}
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult fortressClass::unmountScientificLab()
{
	mountingResult result = this->unmountItemPrepare(this->otherEquipment.scientificLab(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->otherEquipment.unmountScientificLab(), 0);
	}
	return result;
};

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

mountingResult fortressClass::unmountLifeSupport()
{
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->otherEquipment.lifeSupport(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->otherEquipment.unmountLifeSupport(), 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	return result;
};

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

mountingResult fortressClass::unmountSubspaceTransmitter()
{
	mountingResult result = this->unmountItemPrepare(this->otherEquipment.subspaceTransmitter(), 0);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->otherEquipment.unmountSubspaceTransmitter(), 0);
	}
	return result;
};

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

mountingResult baseClass::unmountHangar(dtIdentifier HID)
{
	if (NOT_VALID_ID == HID)
	{
		return MR_SLOT_EMPTY;
	}
	hangarClass * han = actx->cacheItemsList.getItem<hangarClass>(HID);
	han->checkConstruction(this);
	if (!(han->isHangerFree()))
	{
		return MR_HANGAR_NOT_EMPTY;
	}
	mountingResult result = this->unmountItemPrepare(han, 1);
	if (MR_DONE == result)
	{
		this->warehouse.addItem(this->hangarsPort.unmountHangarByID(HID), 0);
	}
	return result;
};

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

mountingResult baseClass::unmountMagneticalFilters(unsigned long long & working, unsigned long long & damaged)
{
	this->quarkGluonPlasmaUpdate();
	mountingResult result = this->unmountItemPrepare(this->factories.magneticalFilter(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->factories.magneticalFilter()->subWorking(working);
		damaged = this->factories.magneticalFilter()->subDamaged(damaged);
		this->warehouse.addItem(this->factories.magneticalFilter(), working, damaged, 0);
	}
	this->quarkGluonPlasmaUpdate();
	return result;
};

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

mountingResult baseClass::unmountDeuteriumDecomposers(unsigned long long & working, unsigned long long & damaged)
{
	this->containeredResourcesUpdate();
	mountingResult result = this->unmountItemPrepare(this->factories.deuteriumDecomposer(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->factories.deuteriumDecomposer()->subWorking(working);
		damaged = this->factories.deuteriumDecomposer()->subDamaged(damaged);
		this->warehouse.addItem(this->factories.deuteriumDecomposer(), working, damaged, 0);
	}
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult baseClass::unmountZirconiumReactors(unsigned long long & working, unsigned long long & damaged)
{
	this->containeredResourcesUpdate();
	this->energyDistributionPhaseAndWeaponsFire();
	mountingResult result = this->unmountItemPrepare(this->factories.zirconiumReactor(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->factories.zirconiumReactor()->subWorking(working);
		damaged = this->factories.zirconiumReactor()->subDamaged(damaged);
		this->warehouse.addItem(this->factories.zirconiumReactor(), working, damaged, 0);
	}
	this->energyDistributionPhaseAndWeaponsFire();
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult baseClass::unmountIlmeniteFurnaces(unsigned long long & working, unsigned long long & damaged)
{
	this->containeredResourcesUpdate();
	mountingResult result = this->unmountItemPrepare(this->factories.ilmeniteFurnace(), working, damaged, 1);
	if (MR_DONE == result)
	{
		working = this->factories.ilmeniteFurnace()->subWorking(working);
		damaged = this->factories.ilmeniteFurnace()->subDamaged(damaged);
		this->warehouse.addItem(this->factories.ilmeniteFurnace(), working, damaged, 0);
	}
	this->containeredResourcesUpdate();
	return result;
};

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

mountingResult fortressClass::unmountItemPrepare(commonItemClass * item, unsigned long long & workingCount, unsigned long long & damagedCount, bool alreadyStoraged)
{
	if (item->isNull())
	{
		return MR_SLOT_EMPTY;
	}

	if (item->isStackable())
	{
		workingCount       = min(workingCount, ((stackableItemClass *)(item))->getWorking());
		damagedCount       = min(damagedCount, ((stackableItemClass *)(item))->getDamaged());
	}
	else
	{
		workingCount       = min(workingCount, (unsigned long long)1);
		damagedCount       = 0;
	}

	unsigned long long mountingPointsRequired = this->mountingPointsRequiredForItemMounting(item, workingCount + damagedCount);

	if ((0 == this->mechanics.androids()->getWorking()     )  &&
		(0 == this->crew.getEffectiveCountOf(CREW_ENGINEER)) &&
		(0 < mountingPointsRequired                        ))
	{
		return MR_NOT_ENOUGH_ANDROIDS;
	}

	unsigned long long energyRequired         = this->energyRequiredForItemMounting(mountingPointsRequired);
	if (this->energyInTJ(1) < energyRequired)
	{
		return MR_NOT_ENOUGH_ENERGY;
	}

	if ((!alreadyStoraged) && (this->freeCapacity() < item->getSize()))
	{
		return MR_NOT_ENOUGH_STORAGE_SPACE;
	}

	return MR_DONE;
};

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

mountingResult fortressClass::unmountItemPrepare(commonItemClass * item, bool alreadyStoraged)
{
	unsigned long long working = 1;
	unsigned long long damaged = 0;
	return this->unmountItemPrepare(item, working, damaged, alreadyStoraged);
};

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

bool fortressClass::getDistanceFrom(fortressClass * target, dist_t & distance)
{
	return fortressClass::distanceBetweenTwoFortresses(this, target, distance);
};

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

bool fortressClass::isTargetInRangeRing0(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->getFortressType() == target->getFortressType())
	{
		return 0;
	}
	baseClass * base = NULL;
	shipClass * ship = NULL;
	if (FT_BASE == this->getFortressType())
	{
		base = (baseClass *)this;
	}
	if (FT_SHIP == this->getFortressType())
	{
		ship = (shipClass *)this;
	}
	if (FT_BASE == target->getFortressType())
	{
		base = (baseClass *)target;
	}
	if (FT_SHIP == target->getFortressType())
	{
		ship = (shipClass *)target;
	}
	if ((!base) || (!ship))
	{
		return 0;
	}

	if ((ship->MovementIsDockedInBase()                       ) &&
		(ship->getShipsDockingBase()                          ) &&
		(ship->getShipsDockingBase()->getID() == base->getID()))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isTargetInRangeRing1(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}
	
	dist_t distance    = 0;
	bool   isReachable = this->getDistanceFrom(target, distance);
	if (!isReachable)
	{
		return 0;
	}
	if (RING1_RANGE_IN_KM < distance)
	{
		return 0;
	}
	else
	{
		return 1;
	}
};

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

bool fortressClass::isTargetInRangeRing2(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dist_t distance    = 0;
	bool   isReachable = this->getDistanceFrom(target, distance);
	if (!isReachable)
	{
		return 0;
	}
	if (RING2_RANGE_IN_KM < distance)
	{
		return 0;
	}
	else
	{
		return 1;
	}
};

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

bool fortressClass::isTargetInRangeRing3(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dtIdentifier firstCenterID  = 0;
	dtIdentifier secondCenterID = 0;
	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		firstCenterID = thisBase->getFortressPlanet()->getID();
	}
	if (FT_SHIP == this->getFortressType())
	{
		shipClass * thisShip = (shipClass *)this;
		if ((!(thisShip->getShipsAreaCenter())                      ) || 
			(SOT_PLANET != thisShip->getShipsAreaCenter()->getType()))
		{
			return 0;
		}
		firstCenterID = thisShip->getShipsAreaCenter()->getID();
	}
	if (FT_BASE == target->getFortressType())
	{
		// STEPAN FIX (baseClass *)this opraveno na (baseClass *)target
		baseClass * targetBase = (baseClass *)target;
		secondCenterID = targetBase->getFortressPlanet()->getID();
	}
	if (FT_SHIP == target->getFortressType())
	{
		shipClass * targetShip = (shipClass *)this;
		if ((!(targetShip->getShipsAreaCenter())                      ) || 
			(SOT_PLANET != targetShip->getShipsAreaCenter()->getType()))
		{
			return 0;
		}
		secondCenterID = targetShip->getShipsAreaCenter()->getID();
	}

	if ((firstCenterID == secondCenterID) &&
		(0 < firstCenterID              ))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isTargetInRangeRing4(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dist_t distance    = 0;
	bool   isReachable = this->getDistanceFrom(target, distance);
	if (!isReachable)
	{
		return 0;
	}
	if (RING4_RANGE_IN_KM < distance)
	{
		return 0;
	}
	else
	{
		return 1;
	}
};

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

bool fortressClass::isTargetInRangeRing5(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dtIdentifier firstCenterID  = 0;
	dtIdentifier secondCenterID = 0;
	if ((FT_BASE == this->getFortressType()  ) ||
		(FT_BASE == target->getFortressType()))
	{
		return 0;
	}
	if (FT_SHIP == this->getFortressType())
	{
		shipClass * thisShip = (shipClass *)this;
		if ((!(thisShip->getShipsAreaCenter())                    ) || 
			(SOT_STAR != thisShip->getShipsAreaCenter()->getType()))
		{
			return 0;
		}
		firstCenterID = thisShip->getShipsAreaCenter()->getID();
	}
	if (FT_SHIP == target->getFortressType())
	{
		shipClass * targetShip = (shipClass *)this;
		if ((!(targetShip->getShipsAreaCenter())                    ) ||
			(SOT_STAR != targetShip->getShipsAreaCenter()->getType()))
		{
			return 0;
		}
		secondCenterID = targetShip->getShipsAreaCenter()->getID();
	}

	if ((firstCenterID == secondCenterID) &&
		(0 < firstCenterID              ))
	{
		return 1;
	}
	else
	{
		return 0;
	}
};

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

bool fortressClass::isTargetInRangeRing6(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dist_t distance    = 0;
	bool   isReachable = this->getDistanceFrom(target, distance);
	if (!isReachable)
	{
		return 0;
	}
	if (RING6_RANGE_IN_KM < distance)
	{
		return 0;
	}
	else
	{
		return 1;
	}
};

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

bool fortressClass::isTargetInRangeRing7(fortressClass * target)
{
	if (!target)
	{
		return 0;
	}
	if (this->isTargetInRangeRing0(target))
	{
		return 1;
	}

	dist_t distance    = 0;
	bool   isReachable = this->getDistanceFrom(target, distance);
	if (!isReachable)
	{
		return 0;
	}
	if (RING7_RANGE_IN_KM < distance)
	{
		return 0;
	}
	else
	{
		return 1;
	}
};

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

void fortressClass::updateClient(bool authoritative)
{
	if ((!authoritative                     ) &&
		(gctx.eng.isClientUpdateSuppressed()))
	{
		return;
	}

	if ((!authoritative                                                                                          ) &&
		(0 < this->clientUpdateTEMP_                                                                             ) &&
		(dv_time::secondsBetween(this->clientUpdateTEMP_, dv_time::now(), 1) < MIN_CLIENT_UPDATE_DELAY_IN_SECONDS))
	{
		return;
	}
	
	updateFortress(this->getID(), this->getFortressRealmID());
};

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

tradingResult fortressClass::commitTrade(fortressClass * firstFortress, tradeBundleClass * firstOffer, fortressClass * secondFortress, tradeBundleClass * secondOffer)
{
	if ((!firstFortress ) ||
		(!firstOffer    ) ||
		(!secondFortress) ||
		(!secondOffer   ))
	{
		return TR_UNKNOWN_FAIL;
	}

	if (!(firstFortress->isInRangeForTrade(secondFortress)))
	{
		return TR_NOT_IN_RANGE;
	}

	if ((firstFortress->isShell(0)) || (secondFortress->isShell(0)))
	{
		if ((firstFortress->isShell(1)) && (secondFortress->isShell(1)))
		{
			return TR_UNKNOWN_FAIL;
		}
		fortressClass    * sourceFortress;
		fortressClass    * targetShell;
		tradeBundleClass * transferBundle;
		if (firstFortress->isShell(1))
		{
			sourceFortress = secondFortress;
			targetShell    = firstFortress;
			transferBundle = secondOffer;
		}
		else
		{
			sourceFortress = firstFortress;
			targetShell    = secondFortress;
			transferBundle = firstOffer;
		}
		if (!(transferBundle->checkStorageOwnershipAndValidity(sourceFortress)))
		{
			TR_FIRST_FORTRESS_NOT_STORING_ITEMS;
		}
		transferBundle->clearBundleToMatchAShell(targetShell);
		sourceFortress->warehouse.transferBundleIntoShell(targetShell, transferBundle);
		targetShell->energyDistributionPhaseAndWeaponsFire();

		return TR_DONE;
	}

	if (!(firstOffer->checkStorageOwnershipAndValidity(firstFortress)))
	{
		return TR_FIRST_FORTRESS_NOT_STORING_ITEMS;
	}
	if (!(secondOffer->checkStorageOwnershipAndValidity(secondFortress)))
	{
		return TR_SECOND_FORTRESS_NOT_STORING_ITEMS;
	}

	firstOffer->updateWeightAndSize(0);
	secondOffer->updateWeightAndSize(0);

	unsigned long long firstFortressFreeWeight  = firstFortress->freeWeight(0, 0, 0);
	unsigned long long secondFortressFreeWeight = secondFortress->freeWeight(0, 0, 0);
	unsigned long long firstOfferWeight         = firstOffer->getTotalWeight();
	unsigned long long secondOfferWeight        = secondOffer->getTotalWeight();
	if ((firstOfferWeight < secondOfferWeight) && (firstFortressFreeWeight < (secondOfferWeight - firstOfferWeight)))
	{
		return TR_FIRST_FORTRESS_WEIGHT_LIMIT;
	}
	if ((secondOfferWeight < firstOfferWeight) && (secondFortressFreeWeight < (firstOfferWeight - secondOfferWeight)))
	{
		return TR_SECOND_FORTRESS_WEIGHT_LIMIT;
	}

	unsigned long long firstFortressFreeSize    = firstFortress->freeCapacity();
	unsigned long long secondFortressFreeSize   = secondFortress->freeCapacity();
	unsigned long long firstOfferSize           = firstOffer->getTotalSize();
	unsigned long long secondOfferSize          = secondOffer->getTotalSize();
	if ((firstOfferSize < secondOfferSize) && (firstFortressFreeSize < (secondOfferSize - firstOfferSize)))
	{
		return TR_FIRST_FORTRESS_CAPACITY_LIMIT;
	}
	if ((secondOfferSize < firstOfferSize) && (secondFortressFreeSize < (firstOfferSize - secondOfferSize)))
	{
		return TR_SECOND_FORTRESS_CAPACITY_LIMIT;
	}

	unsigned long long firstFortressQGPDiff     = firstFortress->freeSpaceForQuarkGluonPlasmaInMiligrams(0, 0);
	unsigned long long secondFortressQGPDiff    = secondFortress->freeSpaceForQuarkGluonPlasmaInMiligrams(0, 0);
	unsigned long long firstOfferQGPOverhead    = firstOffer->quarkGluonPlasmaOverheadInMg();
	unsigned long long secondOfferQGPOverhead   = secondOffer->quarkGluonPlasmaOverheadInMg();
	if ((firstOfferQGPOverhead < secondOfferQGPOverhead) && (firstFortressQGPDiff < (secondOfferQGPOverhead - firstOfferQGPOverhead)))
	{
		return TR_FIRST_FORTRESS_MAGNETICAL_GRIDS_LACK;
	}
	if ((secondOfferQGPOverhead < firstOfferQGPOverhead) && (secondFortressQGPDiff < (firstOfferQGPOverhead - secondOfferQGPOverhead)))
	{
		return TR_SECOND_FORTRESS_MAGNETICAL_GRIDS_LACK;
	}

	unsigned long long firstFortressCRDiff      = firstFortress->freeTransportContainersCapacity(1, 0);
	unsigned long long secondFortressCRDiff     = secondFortress->freeTransportContainersCapacity(1, 0);
	unsigned long long firstOfferCROverhead     = firstOffer->containeredResourcesOverheadInM3();
	unsigned long long secondOfferCROverhead    = secondOffer->containeredResourcesOverheadInM3();
	if ((firstOfferCROverhead < secondOfferCROverhead) && (firstFortressCRDiff < (secondOfferCROverhead - firstOfferCROverhead)))
	{
		return TR_FIRST_FORTRESS_TRANSPORT_CONTAINERS_LACK;
	}
	if ((secondOfferCROverhead < firstOfferCROverhead) && (secondFortressCRDiff < (firstOfferCROverhead - secondOfferCROverhead)))
	{
		return TR_SECOND_FORTRESS_TRANSPORT_CONTAINERS_LACK;
	}

	unsigned long long firstFortressEDiff       = firstFortress->freeSpaceForEnergyInTeraJoules(0, 0);
	unsigned long long secondFortressEDiff      = secondFortress->freeSpaceForEnergyInTeraJoules(0, 0);
	unsigned long long firstOfferEOverhead      = firstOffer->energyOverheadInTJ();
	unsigned long long secondOfferEOverhead     = secondOffer->energyOverheadInTJ();
	if ((firstOfferEOverhead < secondOfferEOverhead) && (firstFortressEDiff < (secondOfferEOverhead - firstOfferEOverhead)))
	{
		return TR_FIRST_FORTRESS_ENERGETIC_CELLS_LACK;
	}
	if ((secondOfferEOverhead < firstOfferEOverhead) && (secondFortressEDiff < (firstOfferEOverhead - secondOfferEOverhead)))
	{
		return TR_SECOND_FORTRESS_ENERGETIC_CELLS_LACK;
	}

	warehouseClass::tradeItemsWithoutAnyControl(&(firstFortress->warehouse), firstOffer, &(secondFortress->warehouse), secondOffer);

	firstFortress->subAllResources (firstOffer->getQuarkGluonPlasmaInMg(),
		                            firstOffer->getUlreaCount(),
									firstOffer->getHeavyWaterInKg(),
									firstOffer->getDeuteriumInKg(),
									firstOffer->getZirconiumCrystalInKg(),
									firstOffer->getEnergyInTJ(),
									firstOffer->getIlmeniteInKg(),
									firstOffer->getTitaniumInKg());
	secondFortress->subAllResources(secondOffer->getQuarkGluonPlasmaInMg(),
		                            secondOffer->getUlreaCount(),
									secondOffer->getHeavyWaterInKg(),
									secondOffer->getDeuteriumInKg(),
									secondOffer->getZirconiumCrystalInKg(),
									secondOffer->getEnergyInTJ(),
									secondOffer->getIlmeniteInKg(),
									secondOffer->getTitaniumInKg());

	firstFortress->addAllResources (secondOffer->getQuarkGluonPlasmaInMg(),
		                            secondOffer->getUlreaCount(),
									secondOffer->getHeavyWaterInKg(),
									secondOffer->getDeuteriumInKg(),
									secondOffer->getZirconiumCrystalInKg(),
									secondOffer->getEnergyInTJ(),
									secondOffer->getIlmeniteInKg(),
									secondOffer->getTitaniumInKg());
	secondFortress->addAllResources(firstOffer->getQuarkGluonPlasmaInMg(),
		                            firstOffer->getUlreaCount(),
									firstOffer->getHeavyWaterInKg(),
									firstOffer->getDeuteriumInKg(),
									firstOffer->getZirconiumCrystalInKg(),
									firstOffer->getEnergyInTJ(),
									firstOffer->getIlmeniteInKg(),
									firstOffer->getTitaniumInKg());
	
	return TR_DONE;
};

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

tradingResult fortressClass::throwSomeStuffIntoTheSpace(tradeBundleClass * someStuff)
{
	if (!someStuff)
	{
		return TR_UNKNOWN_FAIL;
	}

	if (!(someStuff->checkStorageOwnershipAndValidity(this)))
	{
		return TR_FIRST_FORTRESS_NOT_STORING_ITEMS;
	}

	this->warehouse.throwBundleIntoTheSpace(someStuff);
	this->subAllResources(someStuff->getQuarkGluonPlasmaInMg(),
		                  someStuff->getUlreaCount(),
						  someStuff->getHeavyWaterInKg(),
						  someStuff->getDeuteriumInKg(),
						  someStuff->getZirconiumCrystalInKg(),
						  someStuff->getEnergyInTJ(),
						  someStuff->getIlmeniteInKg(),
						  someStuff->getTitaniumInKg());

	return TR_DONE;
};

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

/*
unsigned long fortressClass::transferStorageItemToAnotherFortress(fortressClass * targetFortress, dtIdentifier itemID, unsigned long working, unsigned long damaged)
{
	commonItemClass * sourceItemPtr = (commonItemClass*)(((actx->cacheItemsList))[itemID]);

	if (targetFortress->isShell(0))
	{
		damaged = 0;
		if (typeid(androidsClass) == typeid(*sourceItemPtr))
		{
			unsigned long maxWeightCount   = (unsigned long)((double)targetFortress->loadingWeightLimit()   * (double)SHELL_ANDROIDS_LOADING_LIMIT / (double)this->mechanics.androids()->getSize());
			unsigned long maxSizeCount     = (unsigned long)((double)targetFortress->loadingCapacityLimit() * (double)SHELL_ANDROIDS_LOADING_LIMIT / (double)this->mechanics.androids()->getSize());
			unsigned long maxCount         = min(maxWeightCount, maxSizeCount);
			unsigned long maxTransferCount = ulSafeSub(maxCount, targetFortress->mechanics.androids()->getCount());
			unsigned long transferWorking  = min(maxTransferCount, min(working, this->mechanics.androids()->getWorking()));
			targetFortress->mechanics.mountAndroids((androidsClass *)sourceItemPtr, transferWorking);
			((androidsClass *)(sourceItemPtr))->subWorking(transferWorking);
			if (0 == ((androidsClass *)(sourceItemPtr))->getCount())
			{
				for (dtIdentifierList::iterator litp1 = this->warehouse.storageBegin(); litp1 != this->warehouse.storageEnd(); litp1++)
				{
					if (itemID == (*litp1))
					{
						this->warehouse.removeItemByIteratorAndLeftItInCacheList(litp1);
						actx->cacheItemsList.deleteItem(itemID);
						break;
					}
				}
			}
			return transferWorking;
		}
		if (typeid(energeticCellClass) == typeid(*sourceItemPtr))
		{
			unsigned long maxWeightCount   = (unsigned long)((double)targetFortress->loadingWeightLimit()   * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT / (double)this->warehouse.energeticCell()->getSize());
			unsigned long maxSizeCount     = (unsigned long)((double)targetFortress->loadingCapacityLimit() * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT / (double)this->warehouse.energeticCell()->getSize());
			unsigned long maxCount         = min(maxWeightCount, maxSizeCount);
			unsigned long maxTransferCount = ulSafeSub(maxCount, targetFortress->warehouse.energeticCell()->getCount());
			unsigned long transferWorking  = min(maxTransferCount, min(working, this->warehouse.energeticCell()->getWorking()));
			if (targetFortress->warehouse.nullEnergeticCell())
			{
				targetFortress->warehouse.setEnergeticCellID(actx->cacheItemsList.insertItem(((energeticCellClass *)(sourceItemPtr))->createEmptyCopyOfItemOfTheSameClass()));
			}
			targetFortress->warehouse.energeticCell()->addWorking(transferWorking);
			((energeticCellClass *)(sourceItemPtr))->subWorking(transferWorking);
			return transferWorking;
		}
		return 0;
	}

	if ((NULL == sourceItemPtr) || (NOT_VALID_ID == itemID))
		return 0;

	dtIdentifierList::iterator sourceItemIt = warehouse.storageEnd();
	for (dtIdentifierList::iterator litp1 = warehouse.storageBegin(); litp1 != warehouse.storageEnd(); litp1++)
	{
		if (itemID == (*litp1))
		{
			sourceItemIt = litp1;
			break;
		}
	}
	if (warehouse.storageEnd() == sourceItemIt)
		return 0;

	unsigned long long possibleWeightCount = targetFortress->freeWeight(false) / ullHandleZero(sourceItemPtr->getWeight());
	unsigned long long possibleSizeCount   = targetFortress->freeCapacity()    / ullHandleZero(sourceItemPtr->getSize());
	unsigned long long possibleCount       = min(possibleWeightCount, possibleSizeCount);

	if (0 == possibleCount)
		return 0;

	if (sourceItemPtr->isStackable())
	{
		stackableItemClass * stackableSourceItemPtr = (stackableItemClass*)(sourceItemPtr);
		working = min(working, stackableSourceItemPtr->getWorking());
		damaged = min(damaged, stackableSourceItemPtr->getDamaged());
		working = (unsigned long)min((unsigned long long)working, possibleCount);
		damaged = (unsigned long)min((unsigned long long)damaged, max((unsigned long long)0, ullSafeSub(possibleCount, working)));
		dtIdentifierList::iterator destinationItemIt = targetFortress->warehouse.storageEnd();
		stackableItemClass * stackableDestinationItemPtr = NULL;
		for (dtIdentifierList::iterator litp1 = targetFortress->warehouse.storageBegin(); litp1 != targetFortress->warehouse.storageEnd(); litp1++)
		{
			if (typeid(*sourceItemPtr) == typeid(*(((actx->cacheItemsList))[*litp1])))
			{
				destinationItemIt = litp1;
				stackableDestinationItemPtr = (stackableItemClass*)(((actx->cacheItemsList))[*litp1]);
				break;
			}
		}
		if (targetFortress->warehouse.storageEnd() == destinationItemIt)
		{
			stackableDestinationItemPtr = stackableSourceItemPtr->createEmptyCopyOfItemOfTheSameClass();
			unsigned long stackableDestinationItemID = (actx->cacheItemsList).insertItem(stackableDestinationItemPtr);
			targetFortress->warehouse.addItemFront(stackableDestinationItemID);
			destinationItemIt = targetFortress->warehouse.storageBegin();
		}
		stackableSourceItemPtr->subWorking(working);
		stackableSourceItemPtr->subDamaged(damaged);
		if ((0 == stackableSourceItemPtr->getWorking()) && (0 == stackableSourceItemPtr->getDamaged()))
		{
			warehouse.removeItemByIteratorAndLeftItInCacheList(sourceItemIt);
			(actx->cacheItemsList).deleteItem(itemID);
		}
		if (NULL == stackableDestinationItemPtr)
		{
			errLogicalError("null target item");
		}
		else
		{
			stackableDestinationItemPtr->addWorking(working);
			stackableDestinationItemPtr->addDamaged(damaged);
		}
		return (working + damaged);
	}
	else
	{
		warehouse.removeItemByIteratorAndLeftItInCacheList(sourceItemIt);
		targetFortress->warehouse.addItemFront(itemID);
		return 1; // presouvame jeden item , protoze je separate ( <- neni stackable )
	}
};
*/

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

unsigned long long fortressClass::quarkGluonPlasmaLimitInMiligrams()
{
	return (unsigned long long)(warehouse.magneticalGrid()->getWorking()) *
		   (unsigned long long)(warehouse.magneticalGrid()->actualCapacity());
};

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

unsigned long long fortressClass::commonRawMaterialCapacityLimit()
{
	return (unsigned long long)(warehouse.transportContainer()->getWorking()) *
		   (unsigned long long)(warehouse.transportContainer()->actualCapacity());
};

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

unsigned long long fortressClass::energyLimitInTeraJoules()
{
	return (unsigned long long)(warehouse.energeticCell()->getWorking()) *
		   (unsigned long long)(warehouse.energeticCell()->actualCapacity());
};

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

unsigned long long fortressClass::heavyWaterCapacity(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullUpRound(heavyWater_ / HEAVY_WATER_DENSITY);
	}
	else
	{
		return ullUpRoundDiv(this->heavyWaterInKg(softUpdate), HEAVY_WATER_DENSITY);
	}
};

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

unsigned long long fortressClass::deuteriumCapacity(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullUpRound(deuterium_ / DEUTERIUM_DENSITY);
	}
	else
	{
		return ullUpRoundDiv(this->deuteriumInKg(softUpdate), DEUTERIUM_DENSITY);
	}
};

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

unsigned long long fortressClass::zirconiumCrystalsCapacity(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullUpRound(zirconiumCrystal_ / ZIRCONIUM_CRYSTAL_DENSITY);
	}
	else
	{
		return ullUpRoundDiv(zirconiumCrystalInKg(softUpdate), ZIRCONIUM_CRYSTAL_DENSITY);
	}
};

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

unsigned long long fortressClass::ilmeniteCapacity(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullUpRound(ilmenite_ / ILMENITE_DENSITY);
	}
	else
	{
		return ullUpRoundDiv(ilmeniteInKg(softUpdate), ILMENITE_DENSITY);
	}
};

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

unsigned long long fortressClass::titaniumCapacity(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullUpRound(titanium_ / TITANIUM_DENSITY);
	}
	else
	{
		return ullUpRoundDiv(titaniumInKg(softUpdate), TITANIUM_DENSITY);
	}
};

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

unsigned long long fortressClass::commonRawMaterialCapacity(bool doNotUpdate, bool softUpdate)
{
	return heavyWaterCapacity(doNotUpdate, softUpdate)        +
		   deuteriumCapacity(doNotUpdate, softUpdate)         +
		   zirconiumCrystalsCapacity(doNotUpdate, softUpdate) +
		   ilmeniteCapacity(doNotUpdate, softUpdate)          +
		   titaniumCapacity(doNotUpdate, softUpdate);
};

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

unsigned long long fortressClass::freeTransportContainersCapacity(bool doNotUpdate, bool softUpdate)
{
		return ullSafeSub(commonRawMaterialCapacityLimit(), commonRawMaterialCapacity(doNotUpdate, softUpdate));
};

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

unsigned long long fortressClass::freeSpaceForDeuteriumInKilograms(bool doNotUpdate, bool ignoreWeightOverload, bool softUpdate)
{
	unsigned long long freeCapacity = freeTransportContainersCapacity(doNotUpdate, softUpdate) * (unsigned long long)DEUTERIUM_DENSITY;
	if (ignoreWeightOverload)
	{
		return freeCapacity;
	}
	else
	{
		return min(freeCapacity, freeWeight(1, 0, softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForEnergyInTeraJoules(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullSafeSub(energyLimitInTeraJoules(), (unsigned long long)this->energy_);
	}
	else
	{
		return ullSafeSub(energyLimitInTeraJoules(), energyInTJ(softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForHeavyWaterInKilograms(bool doNotUpdate, bool ignoreWeightOverload, bool softUpdate)
{
	unsigned long long freeCapacity = freeTransportContainersCapacity(doNotUpdate, softUpdate) * (unsigned long long)HEAVY_WATER_DENSITY;
	if (ignoreWeightOverload)
	{
		return freeCapacity;
	}
	else
	{
		return min(freeCapacity, freeWeight(1, 0, softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForIlmeniteInKilograms(bool doNotUpdate, bool ignoreWeightOverload, bool softUpdate)
{
	unsigned long long freeCapacity = freeTransportContainersCapacity(doNotUpdate, softUpdate) * (unsigned long long)ILMENITE_DENSITY;
	if (ignoreWeightOverload)
	{
		return freeCapacity;
	}
	else
	{
		return min(freeCapacity, freeWeight(1, 0, softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForQuarkGluonPlasmaInMiligrams(bool doNotUpdate, bool softUpdate)
{
	if (doNotUpdate)
	{
		return ullSafeSub(quarkGluonPlasmaLimitInMiligrams(), (unsigned long long)this->quarkGluonPlasma_);
	}
	else
	{
		return ullSafeSub(quarkGluonPlasmaLimitInMiligrams(), quarkGluonPlasmaInMg(softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForTitaniumInKilograms(bool doNotUpdate, bool ignoreWeightOverload, bool softUpdate)
{
	unsigned long long freeCapacity = freeTransportContainersCapacity(doNotUpdate, softUpdate) * (unsigned long long)TITANIUM_DENSITY;
	if (ignoreWeightOverload)
	{
		return freeCapacity;
	}
	else
	{
		return min(freeCapacity, freeWeight(1, 0, softUpdate));
	}
};

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

unsigned long long fortressClass::freeSpaceForZirconiumCrystalsInKilograms(bool doNotUpdate, bool ignoreWeightOverload, bool softUpdate)
{
	unsigned long long freeCapacity = freeTransportContainersCapacity(doNotUpdate, softUpdate) * (unsigned long long)ZIRCONIUM_CRYSTAL_DENSITY;
	if (ignoreWeightOverload)
	{
		return freeCapacity;
	}
	else
	{
		return min(freeCapacity, freeWeight(1, 0, softUpdate));
	}
};

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

void fortressClass::addAttackerThatLockedOnThis(dtIdentifier attackerID)
{
	this->attackersThatLockedOnThis_.insert(attackerID);
};

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

void fortressClass::subAttackerThatLockedOnThis(dtIdentifier attackerID)
{
	this->attackersThatLockedOnThis_.erase(attackerID);
};

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

void fortressClass::unlockOutAllAttackersDueToAnnihilation()
{
	for (dtIdentifierSet::iterator litp1 = this->attackersThatLockedOnThis_.begin(); this->attackersThatLockedOnThis_.end() != litp1; litp1++)
	{
		fortressClass * attacker = actx->cacheFortressesList.getItem<fortressClass>(*litp1);
		attacker->targetAnnihilated();
	}
	this->attackersThatLockedOnThis_.clear();
};

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

/*
unsigned long long fortressClass::transferDeuteriumToAnotherFotress(fortressClass * targetFortress, unsigned long long kilograms)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	kilograms = min(kilograms, targetFortress->freeSpaceForDeuteriumInKilograms(0, 0));
	this->subDeuterium(kilograms);
	targetFortress->addDeuterium(kilograms);
	
	return kilograms;
};

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

unsigned long long fortressClass::transferEnergyToAnotherFortress(fortressClass * targetFortress, unsigned long long terajoules)
{
	terajoules = min(terajoules, targetFortress->freeSpaceForEnergyInTeraJoules(0));
	this->subEnergy(terajoules);
	targetFortress->addEnergy(terajoules);

	return terajoules;
};

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

unsigned long long fortressClass::transferHeavyWaterToAnotherFortress(fortressClass * targetFortress, unsigned long long kilograms)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	kilograms = min(kilograms, targetFortress->freeSpaceForHeavyWaterInKilograms(0, 0));
	this->subHeavyWater(kilograms);
	targetFortress->addHeavyWater(kilograms);

	return kilograms;
};

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

unsigned long long fortressClass::transferIlmeniteToAnotherFortress(fortressClass * targetFortress, unsigned long long kilograms)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	kilograms = min(kilograms, targetFortress->freeSpaceForIlmeniteInKilograms(0, 0));
	this->subIlmenite(kilograms);
	targetFortress->addIlmenite(kilograms);

	return kilograms;
};

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

unsigned long long fortressClass::transferQuarkGluonPlasmaToAnotherFortress(fortressClass * targetFortress, unsigned long long miligrams)
{	
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	miligrams = min(miligrams, targetFortress->freeSpaceForQuarkGluonPlasmaInMiligrams(0));
	this->subQuarkGluonPlasma(miligrams);
	targetFortress->addQuarkGluonPlasma(miligrams);

	return miligrams;
};

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

unsigned long long fortressClass::transferTitaniumToAnotherFortress(fortressClass * targetFortress, unsigned long long kilograms)
{
	if (targetFortress->isShell(0))
	{
		if (FT_BASE != targetFortress->getFortressType())
		{
			errLogicalError("Shell is not base (ID %u).", targetFortress->getID());
			return 0;
		}
		baseClass * targetBase = (baseClass *)targetFortress;
		kilograms = min(kilograms, this->titaniumInKg(0));
		kilograms = min(kilograms, targetBase->getWeight() - (targetBase->getWeight() * targetBase->actualBuildingPoints() / targetBase->totalStructuralIntegrity()));
		this->subTitanium(kilograms);
		targetFortress->addTitanium(kilograms);
		return kilograms;
	}

	kilograms = min(kilograms, targetFortress->freeSpaceForTitaniumInKilograms(0, 0));
	this->subTitanium(kilograms);
	targetFortress->addTitanium(kilograms);

	return kilograms;
};

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

unsigned long long fortressClass::transferUlreaToAnotherFortress(fortressClass * targetFortress, unsigned long long count)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	this->subUlrei(count);
	targetFortress->addUlrei(count);

	return count;
};

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

unsigned long long fortressClass::transferZirconiumCrystalsToAnotherFortress(fortressClass * targetFortress, unsigned long long kilograms)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	kilograms = min(kilograms, targetFortress->freeSpaceForZirconiumCrystalsInKilograms(0, 0));
	this->subZirconiumCrystal(kilograms);
	targetFortress->addZirconiumCrystal(kilograms);

	return kilograms;
};

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

unsigned long fortressClass::transferPackedDeuteriumToAnotherFortress(fortressClass * targetFortress, unsigned long containers)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == containers)
		return 0;

	containers = rawMaterialContainersTransferLimit(containers,
		                                            targetFortress->freeWeight(false),
													targetFortress->freeCapacity(),
													deuteriumInKg(0),
													deuteriumSize(1),
													DEUTERIUM_DENSITY,
													heavyWaterSize(1) + zirconiumCrystalSize(1) + ilmeniteSize(1) + titaniumSize(1),
													warehouse.transportContainer()->getCount(),
													warehouse.transportContainer()->getWorking(),
													warehouse.transportContainer()->getWeight(),
													warehouse.transportContainer()->getSize(),
													warehouse.transportContainer()->actualCapacity());

	if (((NULL == targetFortress->warehouse.transportContainer()) || 
		 (targetFortress->warehouse.nullTransportContainer())) && 
		(0 < containers))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	if (0 < containers) // containers nemuze byt vice nez working , protoze to kontroluje transferovaci funkce
	{
		warehouse.transportContainer()->subWorking(containers);
		if (0 == warehouse.transportContainer()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
			warehouse.transportContainer()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.transportContainer()->addWorking(containers);
		unsigned long long deuteriumForTransfer = min(deuteriumInKg(1), (unsigned long long)containers * (unsigned long long)warehouse.transportContainer()->actualCapacity() * (unsigned long long)DEUTERIUM_DENSITY);
		transferDeuteriumToAnotherFotress(targetFortress, deuteriumForTransfer);
		return containers;
	}
	else
	{
		return 0;
	}
};
*/

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

void fortressClass::UpdateEvents()
{
    containeredResourcesTriggerIdentificator_                   = 0;
    energyDistributionPhaseAndWeaponFireTriggerIdentificator_   = 0;
    quarkGluonPlasmaTriggerIdentificator_                       = 0;

    /* provedeme updaty */
    containeredResourcesUpdate();
    energyDistributionPhaseAndWeaponsFire();
    quarkGluonPlasmaUpdate();

    /* provedeme update cile */
    dtIdentifier tId = getWeaponsTargetID();
    if (tId != NOT_VALID_ID)
    {
        fortressClass* fs = actx->cacheFortressesList.getItem<fortressClass>(tId);
        if (fs != NULL)
        {
            fs->addAttackerThatLockedOnThis(getID());
        }
        else
        {
            errLogicalError("Bad target id %u at fortress %u", (unsigned long long)tId, (unsigned long long)getID());
        }
    }
}

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

/*
unsigned long fortressClass::transferPackedEnergyToAnotherFortress(fortressClass * targetFortress, unsigned long cells)
{
	if (targetFortress->isShell(0))
	{
		unsigned long maxWeightCount   = (unsigned long)((double)targetFortress->loadingWeightLimit()   * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT / (double)this->warehouse.energeticCell()->getSize());
		unsigned long maxSizeCount     = (unsigned long)((double)targetFortress->loadingCapacityLimit() * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT / (double)this->warehouse.energeticCell()->getSize());
		unsigned long maxCount         = min(maxWeightCount, maxSizeCount);
		unsigned long maxTransferCount = ulSafeSub(maxCount, targetFortress->warehouse.energeticCell()->getCount());
		unsigned long transferWorking  = min(maxTransferCount, min(cells, this->warehouse.energeticCell()->getWorking()));
		unsigned long long energyLimit = ullUpRoundDiv(this->energyInTJ(0), this->warehouse.energeticCell()->actualCapacity());
		transferWorking                = (unsigned long)min((unsigned long long)transferWorking, (unsigned long long)energyLimit);
		if (targetFortress->warehouse.nullEnergeticCell())
		{
			targetFortress->warehouse.setEnergeticCellID(actx->cacheItemsList.insertItem(this->warehouse.energeticCell()->createEmptyCopyOfItemOfTheSameClass()));
		}
		targetFortress->warehouse.energeticCell()->addWorking(transferWorking);
		this->warehouse.energeticCell()->subWorking(transferWorking);
		unsigned long long energyTransfer =  min((unsigned long long)transferWorking * (unsigned long long)this->warehouse.energeticCell()->actualCapacity(), (unsigned long long)this->energy_);
		this->subEnergy(energyTransfer);
		targetFortress->addEnergy(energyTransfer);
		return transferWorking;
	}

	if ((NULL == warehouse.energeticCell()) || (warehouse.nullEnergeticCell()))
		return 0;

	if (0 == cells)
		return 0;

	if (0 == warehouse.energeticCell()->actualCapacity())
	{
        errLogicalError("Fortress %u: ECs too small", (unsigned long long)this->getID());
		return 0;
	}

	cells =                min(cells, warehouse.energeticCell()->getWorking());
	cells = (unsigned long)min((unsigned long long)cells, (unsigned long long)ullUpRoundDiv(energyInTJ(0), warehouse.energeticCell()->actualCapacity()));


	unsigned long long transferedCellsWeight = (unsigned long long)cells * (unsigned long long)warehouse.energeticCell()->getWeight();
	
	if (targetFortress->freeWeight(false) < transferedCellsWeight) // cilova lod to neunese
	{		
		if (0 == warehouse.energeticCell()->getWeight())
		{
            errLogicalError("Fortress %u: etheric ECs", (unsigned long long)this->getID());
			return 0;
		}
		cells = (unsigned long)min((unsigned long long)cells, (unsigned long long)targetFortress->freeWeight(false) / (unsigned long long)warehouse.energeticCell()->getWeight());
	}


	unsigned long long transferedCellsSize = (unsigned long long)cells * (unsigned long long)warehouse.energeticCell()->getSize();
	
	if (targetFortress->freeCapacity() < transferedCellsSize) // nevejde se to tam
	{
		cells = (unsigned long)min((unsigned long long)cells, (unsigned long long)targetFortress->freeCapacity() / (unsigned long long)warehouse.energeticCell()->getSize());
	}


	if (((NULL == targetFortress->warehouse.energeticCell()) || 
		 (targetFortress->warehouse.nullEnergeticCell())) && 
		(0 < cells))
	{
		energeticCellClass * targetEnergeticCellsPtr = (energeticCellClass *)warehouse.energeticCell()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetEnergeticCellID = (actx->cacheItemsList).insertItem(targetEnergeticCellsPtr);
		targetFortress->warehouse.setEnergeticCellID(targetEnergeticCellID);
	}

	if (0 < cells) // cells nemuze byt vice nez working , coz je uz overeno
	{
		warehouse.energeticCell()->subWorking(cells);
		if (0 == warehouse.energeticCell()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.energeticCell()->getID());
			warehouse.energeticCell()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.energeticCell()->addWorking(cells);
		unsigned long long energyForTransfer = min(energyInTJ(1), (unsigned long long)cells * (unsigned long long)warehouse.energeticCell()->actualCapacity());
		transferEnergyToAnotherFortress(targetFortress, energyForTransfer);
		return cells;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferPackedHeavyWaterToAnotherFortress(fortressClass * targetFortress, unsigned long containers)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == containers)
		return 0;

	containers = rawMaterialContainersTransferLimit(containers,
		                                            targetFortress->freeWeight(false),
													targetFortress->freeCapacity(),
													heavyWaterInKg(0),
													heavyWaterSize(1),
													HEAVY_WATER_DENSITY,
													deuteriumSize(1) + zirconiumCrystalSize(1) + ilmeniteSize(1) + titaniumSize(1),
													warehouse.transportContainer()->getCount(),
													warehouse.transportContainer()->getWorking(),
													warehouse.transportContainer()->getWeight(),
													warehouse.transportContainer()->getSize(),
													warehouse.transportContainer()->actualCapacity());

	if (((NULL == targetFortress->warehouse.transportContainer()) || 
		 (targetFortress->warehouse.nullTransportContainer())) && 
		(0 < containers))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	if (0 < containers) // containers nemuze byt vice nez working , protoze to kontroluje transferovaci funkce
	{
		warehouse.transportContainer()->subWorking(containers);
		if (0 == warehouse.transportContainer()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
			warehouse.transportContainer()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.transportContainer()->addWorking(containers);
		unsigned long long heavyWaterForTransfer = min(heavyWaterInKg(1), (unsigned long long)containers * (unsigned long long)warehouse.transportContainer()->actualCapacity() * (unsigned long long)HEAVY_WATER_DENSITY);
		transferHeavyWaterToAnotherFortress(targetFortress, heavyWaterForTransfer);
		return containers;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferPackedIlmeniteToAnotherFortress(fortressClass * targetFortress, unsigned long containers)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == containers)
		return 0;

	containers = rawMaterialContainersTransferLimit(containers,
		                                            targetFortress->freeWeight(false),
													targetFortress->freeCapacity(),
													ilmeniteInKg(0),
													ilmeniteSize(1),
													ILMENITE_DENSITY,
													heavyWaterSize(1) + deuteriumSize(1) + zirconiumCrystalSize(1) + titaniumSize(1),
													warehouse.transportContainer()->getCount(),
													warehouse.transportContainer()->getWorking(),
													warehouse.transportContainer()->getWeight(),
													warehouse.transportContainer()->getSize(),
													warehouse.transportContainer()->actualCapacity());

	if (((NULL == targetFortress->warehouse.transportContainer()) ||
		 (targetFortress->warehouse.nullTransportContainer())) && 
		(0 < containers))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	if (0 < containers) // containers nemuze byt vice nez working , protoze to kontroluje transferovaci funkce
	{
		warehouse.transportContainer()->subWorking(containers);
		if (0 == warehouse.transportContainer()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
			warehouse.transportContainer()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.transportContainer()->addWorking(containers);
		unsigned long long ilmeniteForTransfer = min(ilmeniteInKg(1), (unsigned long long)containers * (unsigned long long)warehouse.transportContainer()->actualCapacity() * (unsigned long long)ILMENITE_DENSITY);
		transferIlmeniteToAnotherFortress(targetFortress, ilmeniteForTransfer);
		return containers;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferPackedQuarkGluonPlasmaToAnotherFortress(fortressClass * targetFortress, unsigned long grids)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.magneticalGrid()) || (warehouse.nullMagneticalGrid()))
		return 0;

	if (0 == grids)
		return 0;

	if (0 == warehouse.magneticalGrid()->actualCapacity())
	{
        errLogicalError("Fortress %u: MGs too small", (unsigned long long)this->getID());
		return 0;
	}

	grids =                min(grids, warehouse.magneticalGrid()->getWorking());
	grids = (unsigned long)min((unsigned long long)grids, (unsigned long long)ullUpRoundDiv(quarkGluonPlasmaInMg(0), warehouse.magneticalGrid()->actualCapacity()));


	unsigned long long transferedGridsWeight = (unsigned long long)grids * (unsigned long long)warehouse.magneticalGrid()->getWeight();
	
	if (targetFortress->freeWeight(false) < transferedGridsWeight) // cilova lod to neunese
	{		
		grids = (unsigned long)min((unsigned long long)grids, (unsigned long long)targetFortress->freeWeight(false) / (unsigned long long)warehouse.magneticalGrid()->getWeight());
	}


	unsigned long long transferedGridsSize = (unsigned long long)grids * (unsigned long long)warehouse.magneticalGrid()->getSize();
	
	if (targetFortress->freeCapacity() < transferedGridsSize) // nevejde se to tam
	{
		grids = (unsigned long)min((unsigned long long)grids, (unsigned long long)targetFortress->freeCapacity() / (unsigned long long)warehouse.magneticalGrid()->getSize());
	}


	if (((NULL == targetFortress->warehouse.magneticalGrid()) ||
		 (targetFortress->warehouse.nullMagneticalGrid())) && 
		(0 < grids))
	{
		magneticalGridClass * targetMagneticalGridPtr = (magneticalGridClass *)warehouse.magneticalGrid()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetMagneticalGridID = (actx->cacheItemsList).insertItem(targetMagneticalGridPtr);
		targetFortress->warehouse.setMagneticalGridID(targetMagneticalGridID);
	}

	if (0 < grids) // grids nemuze byt vice nez working , coz je uz overeno
	{
		warehouse.magneticalGrid()->subWorking(grids);
		if (0 == warehouse.magneticalGrid()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.magneticalGrid()->getID());
			warehouse.magneticalGrid()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.magneticalGrid()->addWorking(grids);
		unsigned long long quarkGluonPlasmaForTransfer = min(quarkGluonPlasmaInMg(1), (unsigned long long)grids * (unsigned long long)warehouse.magneticalGrid()->actualCapacity());
		transferQuarkGluonPlasmaToAnotherFortress(targetFortress, quarkGluonPlasmaForTransfer);
		return grids;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferPackedTitaniumToAnotherFortress(fortressClass * targetFortress, unsigned long containers)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == containers)
		return 0;

	containers = rawMaterialContainersTransferLimit(containers,
		                                            targetFortress->freeWeight(false),
													targetFortress->freeCapacity(),
													titaniumInKg(0),
													titaniumSize(1),
													TITANIUM_DENSITY,
													heavyWaterSize(1) + deuteriumSize(1) + zirconiumCrystalSize(1) + ilmeniteSize(1),
													warehouse.transportContainer()->getCount(),
													warehouse.transportContainer()->getWorking(),
													warehouse.transportContainer()->getWeight(),
													warehouse.transportContainer()->getSize(),
													warehouse.transportContainer()->actualCapacity());

	if (((NULL == targetFortress->warehouse.transportContainer()) ||
		 (targetFortress->warehouse.nullTransportContainer())) && 
		(0 < containers))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	if (0 < containers) // containers nemuze byt vice nez working , protoze to kontroluje transferovaci funkce
	{
		warehouse.transportContainer()->subWorking(containers);
		if (0 == warehouse.transportContainer()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
			warehouse.transportContainer()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.transportContainer()->addWorking(containers);
		unsigned long long titaniumForTransfer = min(titaniumInKg(1), (unsigned long long)containers * (unsigned long long)warehouse.transportContainer()->actualCapacity() * (unsigned long long)TITANIUM_DENSITY);
		transferTitaniumToAnotherFortress(targetFortress, titaniumForTransfer);
		return containers;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferPackedZirconiumCrystalsToAnotherFortress(fortressClass * targetFortress, unsigned long containers)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == containers)
		return 0;

	containers = rawMaterialContainersTransferLimit(containers,
		                                            targetFortress->freeWeight(false),
													targetFortress->freeCapacity(),
													zirconiumCrystalInKg(0),
													zirconiumCrystalSize(1),
													ZIRCONIUM_CRYSTAL_DENSITY,
													heavyWaterSize(1) + deuteriumSize(1) + ilmeniteSize(1) + titaniumSize(1),
													warehouse.transportContainer()->getCount(),
													warehouse.transportContainer()->getWorking(),
													warehouse.transportContainer()->getWeight(),
													warehouse.transportContainer()->getSize(),
													warehouse.transportContainer()->actualCapacity());

	if (((NULL == targetFortress->warehouse.transportContainer()) || 
		 (targetFortress->warehouse.nullTransportContainer())) && 
		(0 < containers))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	if (0 < containers) // containers nemuze byt vice nez working , protoze to kontroluje transferovaci funkce
	{
		warehouse.transportContainer()->subWorking(containers);
		if (0 == warehouse.transportContainer()->getCount())
		{
			(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
			warehouse.transportContainer()->setID(NOT_VALID_ID);
		}
		targetFortress->warehouse.transportContainer()->addWorking(containers);
		unsigned long long zirconiumCrystalsForTransfer = min(zirconiumCrystalInKg(1), (unsigned long long)containers * (unsigned long long)warehouse.transportContainer()->actualCapacity() * (unsigned long long)ZIRCONIUM_CRYSTAL_DENSITY);
		transferZirconiumCrystalsToAnotherFortress(targetFortress, zirconiumCrystalsForTransfer);
		return containers;
	}
	else
	{
		return 0;
	}
};

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

unsigned long fortressClass::transferEmptyEnergeticCellsToAnotherFortress(fortressClass * targetFortress, unsigned long working, unsigned long damaged)
{
	if (targetFortress->isShell(0))
	{
		unsigned long maxWeightCount   = (unsigned long)((double)targetFortress->loadingWeightLimit()   * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT  / (double)this->warehouse.energeticCell()->getSize());
		unsigned long maxSizeCount     = (unsigned long)((double)targetFortress->loadingCapacityLimit() * (double)SHELL_ENERGETIC_CELLS_LOADING_LIMIT  / (double)this->warehouse.energeticCell()->getSize());
		unsigned long maxCount         = min(maxWeightCount, maxSizeCount);
		unsigned long maxTransferCount = ulSafeSub(maxCount, targetFortress->warehouse.energeticCell()->getCount());
		unsigned long transferWorking  = min(maxTransferCount, min(working, this->warehouse.energeticCell()->getWorking()));
		if (targetFortress->warehouse.nullEnergeticCell())
		{
			targetFortress->warehouse.setEnergeticCellID(actx->cacheItemsList.insertItem(this->warehouse.energeticCell()->createEmptyCopyOfItemOfTheSameClass()));
		}
		targetFortress->warehouse.energeticCell()->addWorking(transferWorking);
		this->warehouse.energeticCell()->subWorking(transferWorking);
		return transferWorking;
	}

	if ((NULL == warehouse.energeticCell()) || (warehouse.nullEnergeticCell()))
		return 0;

	if (0 == warehouse.energeticCell()->actualCapacity())
	{
        errLogicalError("Fortress %u: ECs too small", (unsigned long long)this->getID());
		return 0;
	}

	unsigned long totalWorking = warehouse.energeticCell()->getWorking();
	unsigned long totalDamaged = warehouse.energeticCell()->getDamaged();
	unsigned long totalCharged = (unsigned long)ullUpRoundDiv(energyInTJ(1), (unsigned long long)warehouse.energeticCell()->actualCapacity());
	unsigned long emptyWorking = (unsigned long)ullSafeSub(totalWorking, totalCharged);
	unsigned long emptyDamaged = (unsigned long)ullSafeSub(totalDamaged, ullSafeSub(totalCharged, totalWorking));

	working = min(working, emptyWorking);
	damaged = min(damaged, emptyDamaged);

	if ((0 == warehouse.energeticCell()->getWeight()) || (0 == warehouse.energeticCell()->getSize()))
	{
        errLogicalError("Fortress %u: etheric ECs", (unsigned long long)this->getID());
		return 0;
	}
	
	unsigned long long weightCountLimit   = targetFortress->freeWeight(false) / (unsigned long long)warehouse.energeticCell()->getWeight();
	unsigned long long capacityCountLimit = targetFortress->freeCapacity()    / (unsigned long long)warehouse.energeticCell()->getSize();

	working = (unsigned long)min((unsigned long long)working, weightCountLimit);
	working = (unsigned long)min((unsigned long long)working, capacityCountLimit);
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(weightCountLimit,   working));
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(capacityCountLimit, working));

	if (0 == (working + damaged))
		return 0;

	if ((NULL == targetFortress->warehouse.energeticCell()) || 
		(targetFortress->warehouse.nullEnergeticCell()))
	{
		energeticCellClass * targetEnergeticCellPtr = (energeticCellClass *)warehouse.energeticCell()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetEnergeticCellID = (actx->cacheItemsList).insertItem(targetEnergeticCellPtr);
		targetFortress->warehouse.setEnergeticCellID(targetEnergeticCellID);
	}

	warehouse.energeticCell()->subWorking(working);
	warehouse.energeticCell()->subDamaged(damaged);
	targetFortress->warehouse.energeticCell()->addWorking(working);
	targetFortress->warehouse.energeticCell()->addDamaged(damaged);

	return working + damaged;
};

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

unsigned long fortressClass::transferEmptyMagneticalGridsToAnotherFortress(fortressClass * targetFortress, unsigned long working, unsigned long damaged)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.magneticalGrid()) || (warehouse.nullMagneticalGrid()))
		return 0;

	if (0 == warehouse.magneticalGrid()->actualCapacity())
	{
        errLogicalError("Fortress %u: MGs too small", (unsigned long long)this->getID());
		return 0;
	}

	unsigned long totalWorking = warehouse.magneticalGrid()->getWorking();
	unsigned long totalDamaged = warehouse.magneticalGrid()->getDamaged();
	unsigned long totalCharged = (unsigned long)ullUpRoundDiv(quarkGluonPlasmaInMg(1), (unsigned long long)warehouse.magneticalGrid()->actualCapacity());
	unsigned long emptyWorking = (unsigned long)ullSafeSub(totalWorking, totalCharged);
	unsigned long emptyDamaged = (unsigned long)ullSafeSub(totalDamaged, ullSafeSub(totalCharged, totalWorking));

	working = min(working, emptyWorking);
	damaged = min(damaged, emptyDamaged);
	
	if ((0 == warehouse.magneticalGrid()->getWeight()) || (0 == warehouse.magneticalGrid()->getSize()))
	{
        errLogicalError("Fortress %u: etheric MGs", (unsigned long long)this->getID());
		return 0;
	}

	unsigned long long weightCountLimit   = targetFortress->freeWeight(false) / (unsigned long long)warehouse.magneticalGrid()->getWeight();
	unsigned long long capacityCountLimit = targetFortress->freeCapacity()    / (unsigned long long)warehouse.magneticalGrid()->getSize();

	working = (unsigned long)min((unsigned long long)working, weightCountLimit);
	working = (unsigned long)min((unsigned long long)working, capacityCountLimit);
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(weightCountLimit,   working));
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(capacityCountLimit, working));

	if (0 == (working + damaged))
		return 0;

	if ((NULL == targetFortress->warehouse.magneticalGrid()) || 
		(targetFortress->warehouse.nullMagneticalGrid()))
	{
		magneticalGridClass * targetMagneticalGridPtr = (magneticalGridClass *)warehouse.magneticalGrid()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetMagneticalGridID = (actx->cacheItemsList).insertItem(targetMagneticalGridPtr);
		targetFortress->warehouse.setMagneticalGridID(targetMagneticalGridID);
	}

	warehouse.magneticalGrid()->subWorking(working);
	warehouse.magneticalGrid()->subDamaged(damaged);
	targetFortress->warehouse.magneticalGrid()->addWorking(working);
	targetFortress->warehouse.magneticalGrid()->addDamaged(damaged);

	return working + damaged;
};

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

unsigned long fortressClass::transferEmptyTransportContainersToAnotherFortress(fortressClass * targetFortress, unsigned long working, unsigned long damaged)
{
	if (targetFortress->isShell(0))
	{
		return 0;
	}

	if ((NULL == warehouse.transportContainer()) || (warehouse.nullTransportContainer()))
		return 0;

	if (0 == warehouse.transportContainer()->actualCapacity())
	{
        errLogicalError("Fortress %u: TCs too small", (unsigned long long)this->getID());
	}

	containeredResourcesUpdate();
	unsigned long totalWorking = warehouse.transportContainer()->getWorking();
	unsigned long totalDamaged = warehouse.transportContainer()->getDamaged();
	unsigned long totalCharged = (unsigned long)ullUpRoundDiv(heavyWaterSize(1) + deuteriumSize(1) + zirconiumCrystalSize(1) + ilmeniteSize(1) + titaniumSize(1), (unsigned long long)warehouse.transportContainer()->actualCapacity());
	unsigned long emptyWorking = (unsigned long)ullSafeSub(totalWorking, totalCharged);
	unsigned long emptyDamaged = (unsigned long)ullSafeSub(totalDamaged, ullSafeSub(totalCharged, totalWorking));

	working = min(working, emptyWorking);
	damaged = min(damaged, emptyDamaged);

	if ((0 == warehouse.transportContainer()->getWeight()) || (0 == warehouse.transportContainer()->getSize()))
	{
        errLogicalError("Fortress %u: etheric TCs", (unsigned long long)this->getID());
		return 0;
	}
	
	unsigned long long weightCountLimit   = targetFortress->freeWeight(false) / (unsigned long long)warehouse.transportContainer()->getWeight();
	unsigned long long capacityCountLimit = targetFortress->freeCapacity()    / (unsigned long long)warehouse.transportContainer()->getSize();

	working = (unsigned long)min((unsigned long long)working, weightCountLimit);
	working = (unsigned long)min((unsigned long long)working, capacityCountLimit);
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(weightCountLimit,   working));
	damaged = (unsigned long)min((unsigned long long)damaged, ullSafeSub(capacityCountLimit, working));

	if (0 == (working + damaged))
		return 0;

	if ((NULL == targetFortress->warehouse.transportContainer()) || 
		(targetFortress->warehouse.nullTransportContainer()))
	{
		transportContainerClass * targetTransportContainerPtr = (transportContainerClass *)warehouse.transportContainer()->createEmptyCopyOfItemOfTheSameClass();
		dtIdentifier targetTransportContainerID = (actx->cacheItemsList).insertItem(targetTransportContainerPtr);
		targetFortress->warehouse.setTransportContainerID(targetTransportContainerID);
	}

	warehouse.transportContainer()->subWorking(working);
	warehouse.transportContainer()->subDamaged(damaged);
	targetFortress->warehouse.transportContainer()->addWorking(working);
	targetFortress->warehouse.transportContainer()->addDamaged(damaged);

	return working + damaged;
};

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

unsigned long fortressClass::throwStorageItemToTheSpace(dtIdentifier itemID, unsigned long working, unsigned long damaged)
{
	commonItemClass * sourceItemPtr = (commonItemClass*)(((actx->cacheItemsList))[itemID]);

	if ((NULL == sourceItemPtr) || (NOT_VALID_ID == itemID))
	{
		return 0;
	}

	if (sourceItemPtr->isStackable())
	{
		stackableItemClass * sourceStackableItemPtr = (stackableItemClass *)sourceItemPtr;
		working = min(working, sourceStackableItemPtr->getWorking());
		damaged = min(damaged, sourceStackableItemPtr->getDamaged());
	}
	else
	{
		working = 1;
		damaged = 0;
	}

	dtIdentifierList::iterator itemIterator = this->warehouse.getIteratorByID(itemID);
	if (this->warehouse.storageEnd() == itemIterator)
	{
		return 0;
	}
	this->warehouse.dropItem(itemID, working, damaged, 1);

	return working + damaged;
};

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

unsigned long fortressClass::throwMagneticalGridsToTheSpace(unsigned long working, unsigned long damaged)
{
	working = min(working, warehouse.magneticalGrid()->getWorking());
	damaged = min(damaged, warehouse.magneticalGrid()->getDamaged());

	warehouse.magneticalGrid()->subWorking(working);
	warehouse.magneticalGrid()->subDamaged(damaged);

	if (0 == warehouse.magneticalGrid()->getCount())
	{
		(actx->cacheItemsList).deleteItem(warehouse.magneticalGrid()->getID());
		warehouse.setMagneticalGridID(NOT_VALID_ID);
	}

	return working + damaged;
};

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

unsigned long fortressClass::throwEnergeticCellsToTheSpace(unsigned long working, unsigned long damaged)
{
	working = min(working, warehouse.energeticCell()->getWorking());
	damaged = min(damaged, warehouse.energeticCell()->getDamaged());

	warehouse.energeticCell()->subWorking(working);
	warehouse.energeticCell()->subDamaged(damaged);

	if (0 == warehouse.energeticCell()->getCount())
	{
		(actx->cacheItemsList).deleteItem(warehouse.energeticCell()->getID());
		warehouse.setEnergeticCellID(NOT_VALID_ID);
	}

	return working + damaged;
};

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

unsigned long fortressClass::throwTransportContainersToTheSpace(unsigned long working, unsigned long damaged)
{
	working = min(working, warehouse.transportContainer()->getWorking());
	damaged = min(damaged, warehouse.transportContainer()->getDamaged());

	warehouse.transportContainer()->subWorking(working);
	warehouse.transportContainer()->subDamaged(damaged);

	if (0 == warehouse.transportContainer()->getCount())
	{
		(actx->cacheItemsList).deleteItem(warehouse.transportContainer()->getID());
		warehouse.setTransportContainerID(NOT_VALID_ID);
	}

	return working + damaged;
};

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

unsigned long long fortressClass::throwDeuteriumToTheSpace(unsigned long long kilograms)
{
	this->subDeuterium(kilograms);
	return kilograms;
};

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

unsigned long long fortressClass::throwEnergyToTheSpace(unsigned long long terajoules)
{
	this->subEnergy(terajoules);
	return terajoules;
};

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

unsigned long long fortressClass::throwHeavyWaterToTheSpace(unsigned long long kilograms)
{
	this->subHeavyWater(kilograms);
	return kilograms;
};

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

unsigned long long fortressClass::throwIlmeniteToTheSpace(unsigned long long kilograms)
{
	this->subIlmenite(kilograms);
	return kilograms;
};

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

unsigned long long fortressClass::throwQuarkGluonPlasmaToTheSpace(unsigned long long miligrams)
{
	this->subQuarkGluonPlasma(miligrams);
	return miligrams;
};

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

unsigned long long fortressClass::throwTitaniumToTheSpace(unsigned long long kilograms)
{	
	this->subTitanium(kilograms);
	return kilograms;
};

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

unsigned long long fortressClass::throwUlreaToTheSpace(unsigned long long count)
{
	this->subUlrei(count);
	return count;
};

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

unsigned long long fortressClass::throwZirconiumCrystalsToTheSpace(unsigned long long kilograms)
{
	this->subZirconiumCrystal(kilograms);
	return kilograms;
};
*/

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

unsigned short fortressClass :: getStructuralIntegrityPerc()
{
    const long double ts = (long double)totalStructuralIntegrity();
    const long double si = (long double)structuralIntegrity_;

    return (unsigned short)ceil(100*si/ts);
}

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

unsigned short fortressClass :: getShieldPerc()
{
    const long double en = (long double)deflectorShields.deflectorShieldsGenerator()->actualAccumulator();
    const long double te = (long double)deflectorShields.deflectorShieldsEnergyState.energy;

    if (en == 0)
        return 0;
    else
        return (unsigned short)ceil(100*te/en);
}

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

void fortressClass::globalUpdate()
{
	this->resourcesUpdate(); 
	this->MovementUpdateShipMovementStatus();
	if (FT_BASE == this->getFortressType())
	{
		baseClass * thisBase = (baseClass *)this;
		for (dtIdentifierDeque::const_iterator litp1 = thisBase->hangarsPort.beginHangarsIdentifiers(); thisBase->hangarsPort.endHangarsIdentifiers() != litp1; litp1++)
		{
			hangarClass * hangar = actx->cacheItemsList.getItem<hangarClass>(*litp1);
			hangar->checkConstruction(this);
		}
	}
};

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

bool fortressClass :: getFortressesByPositionEx(const vector_dist_t position, const dist_t radius,
                                    list<dtIdentifier>& ships, list<dtIdentifier>& bases)
{
    /* first, get all stars involved */
    spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);
    if (ns == NULL)
    {
        errLogicalError("Cannot find nearest star for position [%u, %u]!", (unsigned long long)position.x, (unsigned long long)position.y);
        return false;
    }

    spaceRegularObject* nearestStar = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(ns->spaceSystemIndex_);
    if (nearestStar == NULL)
    {
        errLogicalError("Cannot find star with id %u !", (unsigned long long)ns->spaceSystemIndex_);
        return false;
    }

    const dist_t V = (position - nearestStar->getAbsolutePosition()).norm();
    const dist_t R = radius;
    const dist_t M = (V + R) * 2.0L;

    std :: list<dtIdentifier> stars;
    actx->spaceObjectIndex.starsByRegion(position.x - M, position.x + M, position.y - M, position.y + M, stars);

    ships.clear();
    bases.clear();

    for (std :: list<dtIdentifier> :: const_iterator iter = stars.begin(); iter != stars.end(); iter++)
    {
        getFortressesByPositionAndSpaceObject(position, *iter, radius, ships, bases, true);
    }

    return true;
}

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

bool fortressClass :: getFortressesByPositionAndSpaceObject(const vector_dist_t position, const dtIdentifier spObjectIndex,
                                    const dist_t radius, list<dtIdentifier>& myships, list<dtIdentifier>& bases, const bool add)
{
    spaceSunObject* sun = actx->cacheSpaceObjectList.getItem<spaceSunObject>(spObjectIndex);

    if (sun != NULL)
    {
        if (!add)
        {
            myships.clear();
            bases.clear();
        }

        std :: list<dtIdentifier> ships;
        actx->spaceObjectIndex.getShipsInArea(spObjectIndex, ships);

        /* vyfiltrujeme ty lode, ktere jsou v teto oblasti v dosahu pozice */
        for (std :: list<dtIdentifier> :: const_iterator iter = ships.begin(); iter != ships.end(); iter++)
        {
            shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(*iter);
            if (shp != NULL)
            {
                if ((position - shp->MovementGetShipPosition()).norm() < radius)
                    myships.push_back(*iter);
            }
            else
            {
                errLogicalError("Ship with id %u not found!", (unsigned long long)*iter);
                return false;
            }
        }

        /* vyfiltrujeme zakladny */
        for (spaceObject :: dtIdentifierConstIterator iter = sun->subObjectsBegin(); iter != sun->subObjectsEnd(); iter++)
        {
            spacePlanetObject* planet = actx->cacheSpaceObjectList.getItem<spacePlanetObject>(*iter);
            if (planet != NULL)
            {
                if ((position - planet->getAbsolutePosition()).norm() < radius)
                    for (spaceObject :: dtIdentifierConstIterator iter2 = planet->subObjectsBegin();
                        iter2 != planet->subObjectsEnd(); iter2++)
                    {
                        spaceFortressObject* fortress = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(*iter2);
                        if (fortress != NULL)
                            bases.push_back(fortress->getFortressID());
                    }
            }
        }
    }
    else
    {
        errLogicalError("Sun with id %u not found!", (unsigned long long)spObjectIndex);
        return false;
    }

    return true;
}

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

void fortressClass :: getFortressesByPosition(const vector_dist_t position, const dist_t radius,
         list<dtIdentifier>& myships, list<dtIdentifier>& bases)
{
    spaceIndexItem* nearestStarItem = actx->spaceObjectIndex.getNearestItem(position);
    spaceSunObject* sun             = actx->cacheSpaceObjectList.getItem<spaceSunObject>(nearestStarItem->spaceSystemIndex_);

    if (sun != NULL)
    {
        myships.clear();
        bases.clear();

        std :: list<dtIdentifier> ships;
        actx->spaceObjectIndex.getShipsInArea(nearestStarItem->spaceSystemIndex_, ships);

        /* vyfiltrujeme ty lode, ktere jsou v teto oblasti v dosahu pozice */
        for (std :: list<dtIdentifier> :: const_iterator iter = ships.begin(); iter != ships.end(); iter++)
        {
            shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(*iter);
            if (shp != NULL)
            {
                if ((position - shp->MovementGetShipPosition()).norm() < radius)
                    myships.push_back(*iter);
            }
            else
            {
                errLogicalError("Ship with id %u not found!", (unsigned long long)*iter);
            }
        }

        /* vyfiltrujeme zakladny */
        for (spaceObject :: dtIdentifierConstIterator iter = sun->subObjectsBegin(); iter != sun->subObjectsEnd(); iter++)
        {
            spacePlanetObject* planet = actx->cacheSpaceObjectList.getItem<spacePlanetObject>(*iter);
            if (planet != NULL)
            {
                if ((position - planet->getAbsolutePosition()).norm() < radius)
                    for (spaceObject :: dtIdentifierConstIterator iter2 = planet->subObjectsBegin();
                        iter2 != planet->subObjectsEnd(); iter2++)
                    {
                        spaceFortressObject* fortress = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(*iter2);
                        if (fortress != NULL)
                            bases.push_back(fortress->getFortressID());
                    }
            }
        }
    }
    else
    {
        errLogicalError("Sun with id %u not found!", (unsigned long long)nearestStarItem->spaceSystemIndex_);
    }
}

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

bool shipClass::isThereSomeAblePlanetToBuildAShell(spacePlanetObject ** buildingPlanet)
{
	if ((this->MovementIsOrbiting()) &&
		(this->isOrbitingPlanet()  ))
	{
		if (buildingPlanet)
		{
			(*buildingPlanet) = (spacePlanetObject *)(this->getShipsAreaCenter());
		}
		return 1;
	}
	else
	{
		if (buildingPlanet)
		{
			(*buildingPlanet) = NULL;
		}
		return 0;
	}
};

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

void shipClass::shipsAndBasesDamage(unsigned short damagePerc, unsigned short actualStructuralIntegrityPerc, bool & annihilated)
{
	unsigned short damagingCycles;
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_SUBSPACE_DRIVE_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_SUBSPACE_DRIVE_CHANCE))
		{
			subspaceDriveDamage(annihilated);
			if (annihilated)
			{
				return;
			}
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_IMPULS_DRIVE_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_IMPULS_DRIVE_CHANCE))
		{
			impulsDriveDamage(usRollA0ToNSidedDice(HULL_DAMAGE_IMPULS_DRIVE_SIGNIFICANCE));
		}
	}
};

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

unsigned long shipClass::getManoeuvrability()
{
	return (unsigned long)
		   (     (double)getManoeuvrabilityFromMainframe()    *
		    ((double)1 + getManoeuvrabilityBonusFromEngine()) *
		    ((double)1 + getManoeuvrabilityBonusFromPilots()));
};

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

unsigned long shipClass::getManoeuvrabilityFromMainframe()
{
	mainframeClass * mainframe = this->mainframeSystem.mainframe();

	return (unsigned long)
		   ((((double)MAX_TOTAL_SCIENCE_LEVEL / (double)RANGE_MAINFRAME_PREDICTION_MAX       * (double)(mainframe->actualPrediction())) +
		     ((double)MAX_TOTAL_SCIENCE_LEVEL / (double)RANGE_MAINFRAME_TIME_REUSABILITY_MAX * (double)(mainframe->actualTimeReusability()))) /
		    2);
};

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

double shipClass::getManoeuvrabilityBonusFromEngine()
{
	// pro vsechny cisla plati, ze cim vyssi, tim horsi pro manevrovatelnost lodi
	double overloading    = (double)1 - ((double)(this->getWeight())) / ((double)1 + (double)(this->fortressTotalWeightWithPayload(0, 1)));
	// 0 az skoro 1
	double massRating     = this->getFortressClass()->getMassRating();
	// 0 az 1
	double jetRating      = (double)1 - ((double)(this->impulsDrive.impulsJetEngine()->actualForceInGN()) - (double)RANGE_IMPULS_ENGINE_CONSUMPTION_MIN) / ((double)RANGE_IMPULS_ENGINE_FORCE_MAX - (double)RANGE_IMPULS_ENGINE_FORCE_MIN + (double)1);
	// 0 az 1
	return (double)2 - (overloading + massRating + jetRating);
	// -1 a kousek az 2
};

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

double shipClass::getManoeuvrabilityBonusFromPilots()
{
	return (double)2 * (double)(this->crew.getEffectiveCountOf(CREW_PILOT)) / ((double)(this->crew.getEffectiveCountOf(CREW_PILOT)) + (double)25 + (double)128 * (double)this->getFortressClass()->getMassRating());
};

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

unsigned long long shipClass::loadingWeightLimit()
{
	return (unsigned long long)(weight_) * (unsigned long long)(SHIP_LOADING_WEIGHT_LIMIT);
};

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

unsigned long long shipClass::loadingCapacityLimit()
{
	return loadingWeightLimit() / ullHandleZero(MINIMAL_DENSITY_OF_SHIP_CARGO) - 
		   accommodations.getAccomodationsSize();
};

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

unsigned long long shipClass::actualTotalCargoWeight(bool doNotUpdate, bool ignoreResources, bool softUpdate)
{
	unsigned long long result = fortressCoreOnlyCargoWeight(doNotUpdate, ignoreResources, softUpdate);

	result += subspaceDrive.getSubspaceDriveWeight();
	result += impulsDrive.getImpulsDriveWeight();

	return result;
};

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

unsigned long long shipClass::actualSizeOfCargoInWarehouse()
{
	unsigned long long result = fortressCoreOnlySizeOfCargoInWarehouse();

	return result;
};

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

unsigned long long shipClass::freeWeight(bool doNotUpdate, bool ignoreResources, bool softUpdate)
{
	return ullSafeSub(loadingWeightLimit(), actualTotalCargoWeight(doNotUpdate, ignoreResources, softUpdate));
};

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

unsigned long long shipClass::freeCapacity()
{
	return ullSafeSub(loadingCapacityLimit(), actualSizeOfCargoInWarehouse());
};

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

bool shipClass::switchToWarp()
{	
	this->updateUlr();
	unsigned long long QGP = this->quarkGluonPlasmaInMg(0);
	this->subspaceDrive.switchToWarp();
	if (!(this->subspaceDrive.isWorking()))
	{
		return 0;
	}
	if (QGP < this->subspaceDrive.quarkGluonCore()->actualConsumption())
	{
		this->subspaceDrive.jumpOutOfWarp();
		unsigned long long consumption = this->subspaceDrive.quarkGluonCore()->actualConsumption();
		this->subQuarkGluonPlasma(consumption);
		return 0;
	}
	else
	{
		this->updateQGP();
		this->updateUlr();
		return 1;
	}
};

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

void shipClass::jumpOutOfWarp(bool doNotUpdate)
{
	if (!doNotUpdate)
	{
		this->updateQGP();
		this->updateUlr();
	}
	this->subspaceDrive.jumpOutOfWarp();
	if (!doNotUpdate)
	{
		this->updateUlr();
		this->updateQGP();
	}
};

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

void shipClass::fallOutOfWarpDueToQuarkGluonPlasmaLack()
{
	bool annihilated;
	this->jumpOutOfWarp(1);
	this->MovementAfterWarpEmergencyShutdown();
	this->hullDeflection((unsigned long)((double)this->actualStructuralIntegrity() * (double)(rand() % MAX_PERC_DAMAGE_DUE_TO_WARP_FALL_OUT) / (double)HUNDRED_PERCENT), annihilated);
};

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

bool shipClass::fullIgniteImpulsJetEngine()
{
#if defined(DONT_USE_FAKE_ENGINES)
	return this->partitialIgniteImpulsJetEngine(this->impulsDrive.impulsJetEngine()->actualForceInGN());
#else
    return true;
#endif
};

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

bool shipClass::partitialIgniteImpulsJetEngine(unsigned long long force)
{
#if defined(DONT_USE_FAKE_ENGINES)
	unsigned long long deuterium = this->updateDeu();
	this->impulsDrive.partitialIgnite(force);
	if (deuterium < this->impulsDrive.actualConsumption())
	{
		this->impulsDrive.fireOut();
		unsigned long long consumption = this->impulsDrive.actualConsumption();
		this->subDeuterium(consumption);
		return 0;
	}
	else
	{
		this->updateDeu();
		return 1;
	}
#else
    return true;
#endif
};

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

void shipClass::fireOutImpulsJetEngine(bool doNotUpdate)
{
#if defined(DONT_USE_FAKE_ENGINES)
	if ((!doNotUpdate) && (this->impulsDrive.isWorking()))
	{
		this->updateDeu();
		this->impulsDrive.fireOut();
		this->updateDeu();
	}
	else
	{
		this->impulsDrive.fireOut();
	}
#endif
};

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

bool shipClass::isPossibleToQuarryQuarkGluonPlasma(spaceRegularObject ** quarryingPlatform)
{
	if ((0 < this->miningDevices.magneticalCollectorsOfPlasma()->getWorking()         ) &&
		(this->MovementIsOrbiting()                                                   ) &&
		(this->isOrbitingStar()                                                       ) && 
		(WHITE_DWARF == ((spaceSunObject *)(this->getShipsAreaCenter()))->getSunType()) &&
		(this->getDistanceFromSpaceObject(spaceObjectActuallyIn) <= this->miningDevices.magneticalCollectorsOfPlasma()->actualRange(this->getFortressRealmID())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = (spaceRegularObject *)(this->getShipsAreaCenter());
		}
		return 1;
	}
	else
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}
};

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

bool shipClass::isPossibleToQuarryHeavyWater(spaceRegularObject ** quarryingPlatform)
{
	if ((0 < this->miningDevices.submersibleFiltrationTank()->getWorking()) &&
		(this->MovementIsOrbiting()                                       ) &&
		(this->isOrbitingPlanet()                                         ) &&
		(this->getDistanceFromSpaceObject(spaceObjectActuallyIn) <= this->miningDevices.submersibleFiltrationTank()->actualRange(this->getFortressRealmID())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = (spaceRegularObject *)(this->getShipsAreaCenter());
		}
		return 1;
	}
	else
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}
}

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

bool shipClass::isPossibleToQuarryZirconiumCrystal(spaceRegularObject ** quarryingPlatform)
{
	if ((0 < this->miningDevices.submarineMiningMachine()->getWorking()) &&
		(this->MovementIsOrbiting()                                    ) &&
		(this->isOrbitingPlanet()                                      ) &&
		(this->getDistanceFromSpaceObject(spaceObjectActuallyIn) <= this->miningDevices.submarineMiningMachine()->actualRange(this->getFortressRealmID())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = (spaceRegularObject *)(this->getShipsAreaCenter());
		}
		return 1;
	}
	else
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}
}

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

bool shipClass::isPossibleToQuarryIlmenite(spaceRegularObject ** quarryingPlatform)
{
	if ((0 < this->miningDevices.undergroundDrillingMachine()->getWorking()) &&
		(this->MovementIsOrbiting()                                        ) &&
		(this->isOrbitingPlanet()                                          ) &&
		(this->getDistanceFromSpaceObject(spaceObjectActuallyIn) <= this->miningDevices.undergroundDrillingMachine()->actualRange(this->getFortressRealmID())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = (spaceRegularObject *)(this->getShipsAreaCenter());
		}
		return 1;
	}
	else
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}
}

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

bool shipClass::hangShipToOrbit(unsigned long long actualSpeed, unsigned long long targetSpeed)
{
#if defined(DONT_USE_FAKE_ENGINES)
	if (0 == this->impulsDrive.impulsJetEngine()->actualForceInGN())
	{
		return 0;
	}
	unsigned long long requiredSpeedDelta  = max(actualSpeed, targetSpeed) - min(actualSpeed, targetSpeed);
	unsigned long long requiredConsumption = consumptionToStopMovingObject(this->impulsDrive.impulsJetEngine()->actualForceInGN() * GIGA,
		                                                                   this->impulsDrive.impulsJetEngine()->actualConsumption(),
																		   this->actualTotalCargoWeight(0, 0, 1) + this->getWeight(),
																		   requiredSpeedDelta);
	unsigned long long deuterium           = this->updateDeuteriumInKg(1);
	if (deuterium < requiredConsumption)
	{
		return 0;
	}
	else
	{
		this->subDeuterium(requiredConsumption);
		return 1;
	}
#else
    return true;
#endif
};

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

bool shipClass::turnShip(unsigned long long speed, unsigned short angle)
{
#if defined(DONT_USE_FAKE_ENGINES)
	if (180 < angle)
	{
		errLogicalError("ship %u: turn angle gt 180", this->getID());
		return 0;
	}
	if (0 == this->impulsDrive.impulsJetEngine()->actualForceInGN())
	{
		return 0;
	}
	unsigned long long deuterium         = this->updateDeu();
	unsigned long long consumptionToStop = consumptionToStopMovingObject(this->impulsDrive.impulsJetEngine()->actualForceInGN() * GIGA,
		                                                                 this->impulsDrive.impulsJetEngine()->actualConsumption(),
																		 this->actualTotalCargoWeight(0, 0, 1) + this->getWeight(),
																		 speed);
	unsigned long long consumptionToTurn = (unsigned long long)((long double)consumptionToStop / (long double)180 * (long double)angle);
	if (deuterium < consumptionToTurn)
	{
		return 0;
	}
	else
	{
		this->subDeuterium(consumptionToTurn);
		return 1;
	}
#else
    return true;
#endif
};

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

unsigned long long shipClass::slowShip(unsigned long long actualSpeed, unsigned long long targetSpeed)
{
#if defined(DONT_USE_FAKE_ENGINES)
	if (targetSpeed > actualSpeed)
	{
		errLogicalError("ship %u: negative slowing", (unsigned long long)this->getID());
		return actualSpeed;
	}
	if (0 == this->impulsDrive.impulsJetEngine()->actualForceInGN())
	{
		return actualSpeed;
	}
	unsigned long long deuterium         = this->updateDeu();
	unsigned long long consumptionToStop = consumptionToStopMovingObject(this->impulsDrive.impulsJetEngine()->actualForceInGN() * GIGA,
		                                                                 this->impulsDrive.impulsJetEngine()->actualConsumption(),
																		 this->actualTotalCargoWeight(0, 0, 1) + this->getWeight(),
																		 actualSpeed - targetSpeed);
	if (deuterium < consumptionToStop)
	{
		this->subDeuterium(consumptionToStop);
		return ullNumberFromScale(targetSpeed, actualSpeed, 1, 1 - double((long double)deuterium / (long double)consumptionToStop));
	}
	else
	{
		this->subDeuterium(consumptionToStop);
		return targetSpeed;
	}
#else
    return targetSpeed;
#endif
};

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

unsigned long long shipClass::slowShip(unsigned long long actualSpeed, unsigned long long targetSpeed, unsigned long long seconds)
{
#if defined(DONT_USE_FAKE_ENGINES)
	if (!(0 < seconds))
	{
		return this->slowShip(actualSpeed, targetSpeed);
	}
	if (targetSpeed > actualSpeed)
	{
		errLogicalError("ship %u: negative slowing", (unsigned long long)this->getID());
		return actualSpeed;
	}
	double totalWeight = (double)this->fortressTotalWeightWithPayload(0, 1);
	if ((0 == this->impulsDrive.impulsJetEngine()->actualForceInGN()) ||
		(!(0 < totalWeight)                                         ))
	{
		return actualSpeed;
	}
	unsigned long long maxSpeedDelta      = ullUpRound((double)this->impulsDrive.impulsJetEngine()->actualForceInGN() * (double)GIGA / (double)totalWeight * (double)seconds);
	unsigned long long requiredSpeedDelta = actualSpeed - targetShip;
	unsigned long long speedDelta         = min(maxSpeedDelta, requiredSpeedDelta);
	return this->slowShip(actualSpeed, actualSpeed - speedDelta);
#else
    return targetSpeed;
#endif
};

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

void shipClass::switchOffImpulsDueToDeuteriumLack()
{
	this->fireOutImpulsJetEngine(1);
	this->MovementUpdateShipMovementStatus();
};

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

#define CHECK_NULL_SPACE_OBJECT_PTR(x, idship, idobj) if ((x) == NULL)\
    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) (idship), (unsigned long long) (idobj));

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

baseClass * shipClass::getShipsDockingBase()
{
	if (spaceObjectActuallyIn != 0)
    {
        spaceObject* obj = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(obj, getID(), spaceObjectActuallyIn);
		if ((obj != NULL) && (SOT_BASE == obj->getType()))
			return actx->cacheFortressesList.getItem<baseClass>(((spaceFortressObject *)(obj))->getFortressID());
		else
			return NULL;
    }
    return NULL;
};

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

void shipClass :: MovementFreeSpaceUpdateShipPosition(void)
{
    /* zjistime delta casu */
    dv_time:: datetime ct = wt2gt(dv_time:: now());
    dv_time:: datetime dt = ct - lastActualization;

    switch (movementState_)
    {
    case SMS_ORBITING:
        errLogicalError("Ship [%d] orbiting in free space", (unsigned long long) getID());
        break;
    case SMS_STOPPED:
        if (speedNorm != 0)
            errLogicalError("Ship [%d] is moving, but in stopped state", (unsigned long long) getID());
        if (acceleration != 0)
            errLogicalError("Ship [%d] is accelerating, but in stopped state", (unsigned long long) getID());
        break;
    case SMS_REGULAR:
        {
            /* updatujeme pozici lodi */
            const vector_dist_t oldpos = position;
            position = updatePosition(position, course, speedNorm, acceleration, dt);

            /* updatujeme rychlost lodi */
            speedNorm = updateSpeed(speedNorm, acceleration, dt);

            /* osetrime pripad, kdy letime do cile*/
            if (moveTarget == SMT_MOVE_TO_POSITION)
            {
                /* jestlize jsme uletli drahu vetsi, nez vzdalenost k cilovemu mistu, tak nastavime souradnice na cilove misto */
                if ((oldpos - targetPosition).norm() < (oldpos - position).norm())
                {
                    /* jestlize muzeme zastavit, tak zastavime, jinak letime */
                    speedNorm = (dist_t)slowShip((unsigned long long)speedNorm, 0);
                    if (speedNorm == 0)
                    {
                        position = targetPosition;

                        MovementFreeSpaceUpdateTarget();
                        MovementFreeSpaceUpdateAction();
                    }
                }
            }

            if (moveTarget == SMT_MOVE_TO_SHIP)
            {
                // nejdrive zjistime lod, kterou pronasledujeme
                shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(targetShip);
                if (shp != NULL)
                {
                    vector_dist_t tPos = shp->MovementGetShipAbsolutePosition();
                    if ((oldpos - tPos).norm() < (oldpos - position).norm())
                    {
                        position = tPos;

                        if (MovementFreeSpaceChangeCourse(shp->course, false))
                        {
                            dist_t targetSpeed = shp->MovementGetCurrentSpeed();

                            if (targetSpeed > MovementGetCurrentSpeed())
                            {
                                moveAction = SMA_SPACE_ACCELERATE;
                            }
                            else
                                if (targetSpeed < MovementGetCurrentSpeed())
                                {
                                    moveAction = SMA_SPACE_NOTHING;
                                    speedNorm  = (dist_t)slowShip((unsigned long long)speedNorm, (unsigned long long)targetSpeed);
                                }
                        }
                    }
                }
            }

            /* updatujeme cas */
            lastActualization = ct;

            /* updatujeme nejblizsi hvezdu */
            spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);   
            if (ns == NULL)
            {
                errExceptionError("Ship [%u]: nearest star not found!", (unsigned long long) getID());
                break;
            }

            if (ns->spaceSystemIndex_ != nearestStar) 
            {
                /* neblizsi hvezda se zmenila, je nutno upravit datove struktury */
                spaceRegularObject* soNS  = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(nearestStar);
                spaceObject* soNNS        = actx->cacheSpaceObjectList.getItem<spaceObject>(ns->spaceSystemIndex_);
                
                if (soNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) nearestStar);
                if (soNNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);


                /* upravime seznamy hvezd */
                actx->spaceObjectIndex.moveShip(getID(), nearestStar, ns->spaceSystemIndex_);

                nearestStar = ns->spaceSystemIndex_;
            }

            /* jestlize jsme ke hvezde bliz, nez je jeji polomer, lod se znici */
            spaceRegularObject* sobj = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(ns->spaceSystemIndex_);
            if (sobj == NULL)
                errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);
            if ((position - sobj->getAbsolutePosition()).squaredNorm() < sobj->getSquaredObjectRadius())
                MovementCrashShip(sobj->getID());       
        }
        break;
    case SMS_WARP:
        {
        /* ve warpu nejsou pusteny standardni motory ani lod neleti */
        if (speedNorm != 0)
            errLogicalError("Ship [%d] is moving, but in warp state", (unsigned long long) getID());
        if (acceleration != 0)
            errLogicalError("Ship [%d] is accelerating, but in warp state", (unsigned long long) getID());

        /* zjistime, zda jsme warpem doleteli na misto urceni */
        dist_t warpSpeed = MovementGetWarpSpeed();
        dist_t distance  = (position - warpTarget_).norm();
        dv_time:: datetime elapsed = ct - warpStart_;
        dv_time:: datetime needed  = computeTimeForTravelDistance(distance, warpSpeed);
        const vector_dist_t sposT = position;

        if (elapsed > needed)
        {
            /* update state */
            movementState_ = SMS_STOPPED;
            MovementTurnOffWarpEngine();

            /* update position */
            position = warpTarget_;

            /* updatujeme cas */
            lastActualization = ct;

            /* updatujeme nejblizsi hvezdu */
            spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);   
            if (ns == NULL)
            {
                errExceptionError("Ship [%u]: nearest star not found!", (unsigned long long) getID());
                break;
            }

            if (ns->spaceSystemIndex_ != nearestStar) 
            {
                /* neblizsi hvezda se zmenila, je nutno upravit datove struktury */
                spaceRegularObject* soNS  = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(nearestStar);
                spaceObject* soNNS        = actx->cacheSpaceObjectList.getItem<spaceObject>(ns->spaceSystemIndex_);
                
                if (soNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) nearestStar);
                if (soNNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);

                /* upravime seznamy hvezd */
                actx->spaceObjectIndex.moveShip(getID(), nearestStar, ns->spaceSystemIndex_);

                nearestStar = ns->spaceSystemIndex_;
            }

            /* jestlize jsme ke hvezde bliz, nez je jeji polomer, lod se znici */
            spaceRegularObject* sobj = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(ns->spaceSystemIndex_);
            if (sobj == NULL)
                errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);
            if ((position - sobj->getAbsolutePosition()).squaredNorm() < sobj->getSquaredObjectRadius())
                MovementCrashShip(sobj->getID());                 
        }

            // posleme klientovi zpravu
            WarpInfo w;
            vector_dist_t cposEst   = MovementEstimateWarpPosition();
            w.dstPosX               = warpTarget_.x;
            w.dstPosY               = warpTarget_.y;
            w.posX                  = warpTarget_.x;
            w.posY                  = warpTarget_.y;
            w.sposX                 = sposT.x;
            w.sposY                 = sposT.y;
            w.inWarp                = false;
            w.shipId                = getID();
            w.stateChange           = true;
            w.speed                 = MovementGetWarpSpeed();

            gctx.sendToClient(make_pair(getFortressRealmID(), actx->index), answerWriter :: ship_warp_information(w));
        }
        break;
    default:
        errExceptionError("Bad movement state at ship [%u]", (unsigned long long) getID());
    };

    /* updatujeme cas */
    lastActualization = ct;
}

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

vector_dist_t shipClass :: MovementFreeSpaceMovementGetShipPositionAfterTime(const dv_time:: datetime delta)
{
    /* zjistime delta casu */
    dv_time:: datetime ct = wt2gt(dv_time:: now() + delta);
    dv_time:: datetime dt = ct - lastActualization;
    return updatePosition(position, course, speedNorm, acceleration, dt);
}

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

void shipClass :: MovementSpaceObjectUpdateShipPosition(void)
{
    /* jestlize jsme v zakladne, nedeje se nic */
    spaceObject* sobj = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(sobj, getID(), spaceObjectActuallyIn);
    if (sobj == NULL) return;

    if (sobj->getType() == SOT_BASE)
    {
        if (speedNorm != 0)
            errLogicalError("Ship [%d] is moving, but in base", (unsigned long long) getID());
        if (acceleration != 0)
            errLogicalError("Ship [%d] is accelerating, but in base", (unsigned long long) getID());
        if (movementState_ != SMS_STOPPED)
            errLogicalError("Ship [%d] is not stopped, but in base", (unsigned long long) getID());
        return;
    }

    /* zjistime delta casu */
    dv_time:: datetime ct = wt2gt(dv_time:: now());
    dv_time:: datetime dt = ct - lastActualization;

    /* podle stavu pohybu rozlisujeme, co se bude dit */
    switch (movementState_)
    {
    case SMS_ORBITING:
        {
            /* vezmeme nasi hvezdu */
            spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
            CHECK_NULL_SPACE_OBJECT_PTR(sobj, getID(), spaceObjectActuallyIn);

            if (star == NULL) return;

            vector_dist_t courseVect    = position - star->getAbsolutePosition();
            dist_t distance_from_star   = (dist_t)courseVect.norm();       
            dist_t angular_velocity     = computeAngularVelocity(distance_from_star, star->getWeight());
            dist_t basic_angle          = computeBasicAngle(courseVect);

            position                    = updatePositionOrbiting(star->getAbsolutePosition(), distance_from_star,
                                                basic_angle, angular_velocity, dt);
            speedNorm                   = computeOrbitalSpeed(distance_from_star, star->getWeight());
            course                      = courseVect.rotateLeft().normedVector();
        }
        break;
    case SMS_REGULAR:
        {
            /* vezmeme nasi hvezdu */
            spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
            CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);
            if (star == NULL)
                return;        

            /* updatujeme pozici lodi, take vzhledem k gravitacnimu zrychleni hvezdy */
            const vector_dist_t oldpos  = position;
            const dist_t        oldSpd  = speedNorm;
            position                    = updatePosition(oldpos, course, speedNorm, acceleration, dt);
            speedNorm                   = updateSpeed(speedNorm, acceleration, dt);
            const dist_t        oldRad  = MovementSpaceObjectGetGravitationCircleRadius(oldSpd);
            const dist_t        newRad  = MovementSpaceObjectGetGravitationCircleRadius(speedNorm);
            const bool  oldOutsideOfGC  = oldRad < (oldpos - star->getAbsolutePosition()).norm();
            const bool  newOutsideOfGC  = newRad < (position - star->getAbsolutePosition()).norm();

            // pokud jsme protli kruznici, tak zacneme krouzit
            if (oldOutsideOfGC && (!newOutsideOfGC))
            {
                // protli jsme kruznici, zacneme krouzit
                MovementSpaceObjectActionOrbit();
            }
            else
            {
                if (!oldOutsideOfGC && !newOutsideOfGC)
                {
                    vector_dist_t medPt         = (oldpos + position) / 2;
                    dist_t r                    = (star->getAbsolutePosition() - medPt).norm();
                    dist_t gacc                 = r > 1 ? computeGravityAcceleration(r, star->getWeight()) : 0;
                    vector_dbl_t gcourse        = (star->getPosition() - medPt).normedVector();
                    position                    = updatePosition(position, gcourse, gravitationSpeedNorm, 0, dt);
                    gravitationSpeedNorm        = updateSpeed(gravitationSpeedNorm, gacc, dt);

                    /* pokusime se snizit gravitacni rychlost */
                    gravitationSpeedNorm        = (dist_t)slowShip((unsigned long long)gravitationSpeedNorm, 0, dv_time :: secondsOf(dt) + 1);
                    if (gravitationSpeedNorm != 0)
                        position                    = updatePosition(position, gcourse, 0, gacc, dt);

                    /* musime na zaklade gravitationSpeedNorm upravit slozku hlavni rychlosti */
                    dist_t speedPart            = (course * gcourse) * gravitationSpeedNorm;
                    gravitationSpeedNorm       -= speedPart < 0 ? -speedPart : speedPart;
                    speedNorm                  += speedPart;

                    /* updatujeme rychlost */
                    speedNorm                   = updateSpeed(speedNorm, acceleration, dt);

                    /* pokusime se snizit gravitacni rychlost */
                    gravitationSpeedNorm        = (dist_t)slowShip((unsigned long long)gravitationSpeedNorm, 0, dv_time :: secondsOf(dt) + 1);
                }

                /* osetrime pripad, kdy letime do cile*/
                if (!MovementIsInWarp())
                {
                    switch (moveTarget)
                    {
                        case  SMT_MOVE_TO_POSITION:
                            /* jestlize jsme uletli drahu vetsi, nez vzdalenost k cilovemu mistu, tak nastavime souradnice na cilove misto */
                            if ((oldpos - targetPosition).norm() < (oldpos - position).norm())
                            {
                                /* jestlize muzeme zastavit, tak zastavime, jinak letime */
                                speedNorm = (dist_t)slowShip((unsigned long long)speedNorm, 0);
                                if (speedNorm == 0)
                                {
                                    position = targetPosition;

                                    MovementSpaceObjectUpdateTarget();
                                }
                            }
                            break;
                        case SMT_MOVE_TO_SHIP:
                            {
                                // nejdrive zjistime lod, kterou pronasledujeme
                                shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(targetShip);
                                if (shp != NULL)
                                {
                                    vector_dist_t tPos = shp->MovementGetShipAbsolutePosition();
                                    if ((oldpos - tPos).norm() < (oldpos - position).norm())
                                    {
                                        position = tPos;

                                        MovementSpaceObjectUpdateTarget();
                                    }
                                }
                            }
                            break;
                        case SMT_MOVE_TO_SPACE_OBJECT:
                            {
#if 0
                                if (targetSpaceObject == spaceObjectActuallyIn)
                                    break;

                                /* jestlize jsme uletli vetsi drahu, nez vzdalenost k cilovemu objektu, vyresime to */
                                spaceObject* tObj = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
                                if (tObj == NULL)
                                    break;

                                if (tObj->getType() == SOT_BASE)
                                    tObj = tObj->getParentSpaceObjectInstance();

                                spaceRegularObject* rObj = dynamic_cast<spaceRegularObject*>(tObj);
                                if (rObj == NULL)
                                    break;

                                
                                /* jestli jsme dostatecne blizko, osetrme tento pripad */
                                const vector_dist_t dstPos = rObj->getAbsolutePosition();
                                if ((oldpos - dstPos).norm() - rObj->getAreaRadius() * 0.5L < (oldpos - position).norm())
                                {
                                    /* jestlize muzeme zastavit, tak zastavime */
                                    speedNorm = (dist_t)slowShip((unsigned long long)speedNorm, 0);
                                    if (speedNorm == 0)
                                    {
                                        const vector_dist_t crs = (oldpos - dstPos).normedVector();
                                        position = dstPos + crs * (rObj->getAreaRadius() * 0.5L);

                                        MovementSpaceObjectEnterIntoOtherObject(targetSpaceObject);

                                        MovementSpaceObjectUpdateTarget();
                                        MovementSpaceObjectUpdateAction();
                                    }
                                }

#endif

                                MovementSpaceObjectUpdateTarget();

                                break;
                            } /* of case */
                        default:
                            break;
                    } /* of switch */
               } /* of if !warp */
           } /* of if grav. kruh */
        } /* of case */
        break;
    case SMS_STOPPED:
        {
        if (speedNorm != 0)
            errLogicalError("Ship [%d] is moving, but in stopped state", (unsigned long long) getID());
        if (acceleration != 0)
            errLogicalError("Ship [%d] is accelerating, but in stopped state", (unsigned long long) getID());
        if (gravitationSpeedNorm != 0)
            errLogicalError("Ship [%d] has nonzero gravitational speed, but in stopped state", (unsigned long long) getID());

        /* vezmeme nasi hvezdu */
        spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);

        /* musime prekonat gravitacni silu */
        dist_t r            = (star->getAbsolutePosition() - position).norm();
        if (!MovementTurnOnEngineForGravityAnnulating(computeGravityAcceleration(r, star->getWeight())))
        {
            movementState_ = SMS_REGULAR;
        }

        }
        break;
    case SMS_WARP:
        {
        /* ve warpu nejsou pusteny standardni motory ani lod neleti */
        if (speedNorm != 0)
            errLogicalError("Ship [%d] is moving, but in warp state", (unsigned long long) getID());
        if (acceleration != 0)
            errLogicalError("Ship [%d] is accelerating, but in warp state", (unsigned long long) getID());
        if (gravitationSpeedNorm != 0)
            errLogicalError("Ship [%d] has nonzero gravitational speed, but in warp state", (unsigned long long) getID());

        /* zjistime, zda jsme warpem doleteli na misto urceni */
        dist_t warpSpeed = MovementGetWarpSpeed();
        dist_t distance  = (position - warpTarget_).norm();
        dv_time:: datetime elapsed = ct - warpStart_;
        dv_time:: datetime needed  = computeTimeForTravelDistance(distance, warpSpeed);
        const vector_dist_t sposT = position;
        if (elapsed > needed)
        {
            /* update state */
            movementState_ = SMS_STOPPED;
            MovementTurnOffWarpEngine();

            /* update position */
            position = warpTarget_;

            /* updatujeme cas */
            lastActualization = ct;

            /* updatujeme nejblizsi hvezdu */
            spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);   
            if (ns == NULL)
            {
                errExceptionError("Ship [%u]: nearest star not found!", (unsigned long long) getID());
                break;
            }

            if (ns->spaceSystemIndex_ != nearestStar) 
            {
                /* neblizsi hvezda se zmenila, je nutno upravit datove struktury */
                spaceRegularObject* soNS  = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(nearestStar);
                spaceObject* soNNS        = actx->cacheSpaceObjectList.getItem<spaceObject>(ns->spaceSystemIndex_);
                
                if (soNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) nearestStar);
                if (soNNS == NULL)
                    errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);

                /* upravime seznamy hvezd */
                actx->spaceObjectIndex.moveShip(getID(), nearestStar, ns->spaceSystemIndex_);

                nearestStar = ns->spaceSystemIndex_;
            }

            /* jestlize jsme ke hvezde bliz, nez je jeji polomer, lod se znici */
            spaceRegularObject* sobj = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(ns->spaceSystemIndex_);
            if (sobj == NULL)
                errExceptionError("Ship [%u]: star object [%u] not found!", (unsigned long long) getID(), (unsigned long long) ns->spaceSystemIndex_);
            if ((position - sobj->getAbsolutePosition()).squaredNorm() < sobj->getSquaredObjectRadius())
                MovementCrashShip(sobj->getID());  

            // zacneme obihat
            moveTarget = SMT_STOP;
            MovementSpaceObjectUpdateTarget();

            // posleme klientovi zpravu
            WarpInfo w;
            w.dstPosX               = warpTarget_.x;
            w.dstPosY               = warpTarget_.y;
            w.posX                  = warpTarget_.x;
            w.posY                  = warpTarget_.y;
            w.sposX                 = sposT.x;
            w.sposY                 = sposT.y;
            w.inWarp                = false;
            w.shipId                = getID();
            w.stateChange           = true;
            w.speed                 = 0;

            gctx.sendToClient(make_pair(getFortressRealmID(), actx->index), answerWriter :: ship_warp_information(w));
        }
        }
        break;
    default:
        errExceptionError("Bad movement state at ship [%u]", (unsigned long long) getID());
    }

    /* updatujeme cas */
    lastActualization = ct;
}

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

vector_dist_t shipClass :: MovementSpaceObjectMovementGetShipPositionAfterTime(const dv_time:: datetime delta)
{
    /* zjistime delta casu */
    dv_time:: datetime ct = wt2gt(dv_time:: now() + delta);
    dv_time:: datetime dt = ct - lastActualization;
    spaceRegularObject* star        = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);
    if (star == NULL)
        return vector_dist_t(0, 0);

    switch (movementState_)
    {
    case SMS_STOPPED:
        return position;
    case SMS_WARP:
        errLogicalError("Query on ship position in warp at ship [%u]", (unsigned long long)getID());
        return vector_dist_t(0, 0);
    case SMS_REGULAR:
        {
            /* updatujeme pozici lodi, take vzhledem k gravitacnimu zrychleni hvezdy */
            const vector_dist_t oldpos  = position;
            vector_dist_t newpos        = updatePosition(oldpos, course, speedNorm, acceleration, dt);
            vector_dist_t medPt         = (oldpos + newpos) / 2;
            dist_t r                    = (star->getAbsolutePosition() - medPt).norm();
            dist_t gacc                 = computeGravityAcceleration(r, star->getWeight());
            vector_dbl_t vpos           = (convert_vec<double, dist_t>(star->getPosition() - medPt));
            return updatePosition(newpos, vpos.normedVector(), gravitationSpeedNorm, gacc, dt);
        }
    case SMS_ORBITING:
        {
            /* vezmeme nasi hvezdu */  
            vector_dist_t courseVect    = star->getAbsolutePosition() - position;
            dist_t distance_from_star   = (dist_t)courseVect.norm();       
            dist_t angular_velocity     = computeAngularVelocity(distance_from_star, star->getWeight());
            dist_t basic_angle          = computeBasicAngle(courseVect);

            return updatePositionOrbiting(star->getAbsolutePosition(), distance_from_star, basic_angle, angular_velocity, dt);
        }
    default:
        errExceptionError("Bad movement state at ship [%u]", (unsigned long long) getID());
        return vector_dist_t(0, 0);
    }
}

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

bool shipClass :: MovementGetTrackTime(dist_t track, dv_time:: datetime& result)
{
    if (acceleration == 0 && speedNorm == 0)
    {
        return false;
    }

    if (acceleration == 0)
    {
        result = computeTimeForTravelDistance(track, speedNorm);
        return true;
    }

    /* pokud je akcelerace nenulova, spocita se to jinak */
    dist_t dsc = speedNorm * speedNorm - 2 * acceleration * track;
    if (dsc < 0) return false;

    dv_time:: datetime t1 = convertSecondsToDatetime(((-(double)speedNorm - sqrt((double)dsc)) / (double)acceleration));
    dv_time:: datetime t2 = convertSecondsToDatetime(((-(double)speedNorm + sqrt((double)dsc)) / (double)acceleration));

    if ((double)t1 > 0)
    {
        result = t1;
        return true;
    }

    if ((double)t2 > 0)
    {
        result = t2;
        return true;
    }

    return false;
}

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

void shipClass :: MovementFreeSpaceCheckRefreshEvents(void)
{
    /* pozn. pozice lodi MUSI byt aktualni !!! */
    std :: vector<dv_time:: datetime> mintimes;

    /* zjistime, kdy se lod priblizi k nejake hranici oblasti */
    spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);
    if (ns == NULL)
    {
        errExceptionError("Nearest space object not found for ship [%u]", (unsigned long long) getID());
        return;
    }

    /*vector_dist_t crosspoint;
    if (ns->getNearestCrossingPoint(course, position, crosspoint)) 
    {
        dist_t distance = (dist_t)sqrt((double)(crosspoint-position).squaredNorm());
        dv_time:: datetime mintime;
        if (MovementGetTrackTime(distance, mintime))
            mintimes.push_back(mintime);
    }*/

    /* dame tam max. cas 10 sekund na refresh... pokud je rychlost/zrychleni nenulove*/
    mintimes.push_back(wt2gtRelative((double)dv_time:: datetime :: minute() / 6.0L));

    /* dame tam limit zazehnuti motoru */
    dv_time :: datetime diff = engineLimit_ - wt2gt(dv_time :: now());
    if ((double)diff > 0)
    {
        mintimes.push_back(diff);
    }

    /* pokud pronasledujeme, nastavime 1 sekundu na refresh... */
    if (moveTarget == SMT_MOVE_TO_SHIP)
        mintimes.push_back(wt2gtRelative((double)dv_time:: datetime :: second()));

    /* pokud zastavujeme, zjistime, kdy lod zastavi */
    /*if (moveAction == SMA_SPACE_STOP)
    {
        if (speedNorm != 0.0 && acceleration < 0)
        {
            dv_time:: datetime mintime = - (double)speedNorm / (double)acceleration;
            assert((double)mintime > 0.0L);
            mintimes.push_back(mintime);
        }
    }*/

    /* dame tam max. cas za ktery lod preletne do cile */
    dv_time :: datetime esttime = MovementEstimationTime(MovementEstimationDistance());
    if ((double)esttime > (double)dv_time :: datetime :: second() / 3.0L)
        mintimes.push_back(esttime);

    /* nastavime event */
    if (mintimes.size() != 0)
    {
        std :: sort(mintimes.begin(), mintimes.end());
        dv_time:: datetime resulttime = wt2gt(dv_time:: now()) +* mintimes.begin();
        MovementCheckMobilityEvent(resulttime);
    }
}

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

void shipClass :: MovementSpaceObjectCheckRefreshEvents(void)
{
    /* pozn. pozice lodi MUSI byt aktualni !!! */
    std :: vector<dv_time:: datetime> mintimes;

    /* dame tam max. cas 10 realnych sekund na refresh... pokud je rychlost/zrychleni nenulove*/
    mintimes.push_back(wt2gtRelative((double)dv_time:: datetime :: minute() * 8));

    /* pokud pronasledujeme, nastavime 1 sekundu na refresh... */
    if (moveTarget == SMT_MOVE_TO_SHIP)
        mintimes.push_back(wt2gtRelative((double)dv_time:: datetime :: second()));

    /* dame tam limit zazehnuti motoru */
    dv_time :: datetime diff = engineLimit_ - wt2gt(dv_time :: now());
    if ((double)diff > 0)
    {
        mintimes.push_back(diff);
    }

    /* dame tam max. cas za ktery lod preletne do cile */
    dist_t distance = numeric_limits<dist_t> :: infinity();
    switch (moveTarget)
    {
    case SMT_MOVE_TO_POSITION:
        distance = (targetPosition - position).norm();
        break;
    case SMT_MOVE_TO_SPACE_OBJECT:
        spaceObject* so = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
        CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), targetSpaceObject);

        if (so != NULL)
        {
            distance = (so->getAbsolutePosition() - position).norm();
        }

        break;
    };

    if (distance != numeric_limits<dist_t> :: infinity() && movementState_ != SMS_ORBITING)
    {
        dv_time :: datetime esttime = MovementEstimationTime(distance);
        if ((double)esttime > 0)
            mintimes.push_back(esttime);
    }

    /* zjistime, kdy potencionalne prekrocime kruznici */
    if (movementState_ == SMS_REGULAR)
    {
        spaceRegularObject* pivobj = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(pivobj, getID(), spaceObjectActuallyIn);
        if (pivobj == NULL)
            return;   

        const vector_dist_t pivot = pivobj->getAbsolutePosition();

        if (MovementSpaceObjectIsOutsideOfGC(position, speedNorm))
        {            
            unsigned long minSec = 1;
            unsigned long maxSec = 28800;

            while ( minSec != maxSec || minSec == maxSec - 1 )
            {
                const unsigned long medSec      = (minSec + maxSec) / 2;

                // spocitame drahu a rychlost
                const dv_time :: datetime dtime = medSec * dv_time :: datetime :: second();
                const vector_dist_t nPos        = updatePosition(position, course, speedNorm, acceleration, dtime) + pivot;
                const dist_t nSpeed             = updateSpeed(speedNorm, acceleration, dtime);

                if (!MovementSpaceObjectIsOutsideOfGC(nPos, nSpeed))
                {
                    maxSec = medSec;
                }
                else
                {
                    minSec = (minSec != maxSec - 1) ? medSec : maxSec;
                }
            }

            const unsigned long resultSec = minSec;
            const dv_time :: datetime dtime = resultSec * dv_time :: datetime :: second();
            const vector_dist_t nPos        = updatePosition(position, course, speedNorm, acceleration, dtime) + pivot;
            const dist_t nSpeed             = updateSpeed(speedNorm, acceleration, dtime);

            if (!MovementSpaceObjectIsOutsideOfGC(nPos, nSpeed))
            {
                mintimes.push_back(dtime);
            }
        } 
        else
        {
            /* najdeme dobu, kdy potencionalne vyletneme z kruznice */
            unsigned long minSec = 1;
            unsigned long maxSec = 28800;

            while ( minSec != maxSec || minSec == maxSec - 1 )
            {
                const unsigned long medSec      = (minSec + maxSec) / 2;

                // spocitame drahu a rychlost
                const dv_time :: datetime dtime = medSec * dv_time :: datetime :: second();
                const vector_dist_t nPos        = updatePosition(position, course, speedNorm, acceleration, dtime) + pivot;
                const dist_t nSpeed             = updateSpeed(speedNorm, acceleration, dtime);

                if (MovementSpaceObjectIsOutsideOfGC(nPos, nSpeed))
                {
                    maxSec = medSec;
                }
                else
                {
                    minSec = (minSec != maxSec - 1) ? medSec : maxSec;
                }
            }

            const unsigned long resultSec = minSec;
            const dv_time :: datetime dtime = resultSec * dv_time :: datetime :: second();
            const vector_dist_t nPos        = updatePosition(position, course, speedNorm, acceleration, dtime) + pivot;
            const dist_t nSpeed             = updateSpeed(speedNorm, acceleration, dtime);

            if (MovementSpaceObjectIsOutsideOfGC(nPos, nSpeed))
            {
                mintimes.push_back(dtime);
            }
        }
    }

    /* nastavime event */
    if (mintimes.size() != 0 && !MovementIsDockedInBase())
    {
        std :: sort(mintimes.begin(), mintimes.end());
        dv_time:: datetime resulttime = wt2gt(dv_time:: now()) +* mintimes.begin();

        MovementCheckMobilityEvent(resulttime);
    }
}

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

bool shipClass :: MovementFreeSpaceChangeCourse(const vector_dbl_t& vect, bool updatePos)
{
    /* aktualizujeme pozici */
    if (updatePos)
        MovementFreeSpaceUpdateShipPosition();

    /* zmenit kurs jde jen v STOPPED a REGULAR stavech */
    if (movementState_ == SMS_STOPPED || movementState_ == SMS_REGULAR)
    {
        /* spocitame podil uhlu o ktery se mame otocit do 180 stupnu */
        const double cosOfAngle = vect * course;
        const double cm1        = (cosOfAngle - 1) / 2.0L; // cm1 vyjadruje pomernou cast uhlu do 180 stupnu
        const double al         = cm1 < 0 ? -cm1 : cm1;

        if (MovementTurnEnginesForChangeCourse(al))
        {
            course = vect;
            MovementFreeSpaceCheckRefreshEvents();
            return true;
        }
    }

    return false;
}

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

bool shipClass :: MovementSpaceObjectChangeCourse(const vector_dbl_t& vect, bool updatePos)
{
    /* aktualizujeme pozici */
    if (updatePos)
        MovementSpaceObjectUpdateShipPosition();

    /* zmenit kurs jde jen v STOPPED a REGULAR stavech */
    //if (movementState_ == SMS_STOPPED || movementState_ == SMS_REGULAR)
    {
        /* spocitame podil uhlu o ktery se mame otocit do 180 stupnu */
        const double cosOfAngle = vect * course;
        const double cm1        = (cosOfAngle - 1) / 2.0L; // cm1 vyjadruje pomernou cast uhlu do 180 stupnu
        const double al         = cm1 < 0 ? -cm1 : cm1;

#if defined(DONT_USE_FAKE_ENGINES)
        if (MovementTurnEnginesForChangeCourse(al))
        {
#endif
            course = vect;
            MovementSpaceObjectCheckRefreshEvents();
            return true;
#if defined(DONT_USE_FAKE_ENGINES)
        }
#endif
    }

    return false;
}

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

bool shipClass :: MovementFreeSpaceMustEnterStarSystem(const vector_dist_t& pos, const dist_t speed)
{
    /* napred ziskame pozici lodi v hvezdnem systemu, ktery se ale mohl zmenit, najdeme nejblizsi hvezdu */
    spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(pos);
    if (ns == NULL)
    {
        errExceptionError("Nearest space object not found for ship [%u]", (unsigned long long) getID());
        return false;
    }

    spaceRegularObject* so = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(ns->spaceSystemIndex_);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), ns->spaceSystemIndex_);
    if (so == NULL)
        return false;

    /* pokud je lod dostatecne vzdalena, vrat false */
    if ((pos - so->getAbsolutePosition()).squaredNorm() > so->getSquaredAreaRadius())
        return false;

    /* jsme blizko slunecni soustavy, pokud chceme vstoupit, vrat true */
    if (wantEnterSpaceObject) 
        return true;

    /* jestlize jsme blize, nez 2x polomer hvezdy, vstup vynucene */
    if ((pos - so->getAbsolutePosition()).squaredNorm() <= 2.0L * so->getSquaredObjectRadius())
        return true;

    /* jestlize je rychlost prilis nizka, vstup vynucene */
    if (so->getOrbitingSpeed(pos) >= speed)
        return true;

    return false;
}

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

void shipClass :: MovementFreeSpaceEnterIntoSolarSystem(dtIdentifier starSystemId)
{
    /* napred ziskame pozici lodi v hvezdnem systemu */
    spaceRegularObject* so = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(starSystemId);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), starSystemId);
    if (so == NULL)
        return;

    /* nastavime novou hvezdnou soustavu */
    spaceObjectActuallyIn = starSystemId;

    /* prenastavime akce */
    switch (moveAction)
    {
    case SMA_SPACE_STOP:            moveAction = SMA_SPACE_OBJECT_STOP;          break;
    case SMA_SPACE_NOTHING:         moveAction = SMA_SPACE_OBJECT_NOTHING;       break;
    case SMA_SPACE_ACCELERATE:      moveAction = SMA_SPACE_OBJECT_ACCELERATE;    break;
    default:
        moveAction = SMA_SPACE_OBJECT_NOTHING;
    }
}

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

void shipClass :: MovementSpaceObjectEnterIntoOtherObject(dtIdentifier spaceObjectID)
{
    /* musime rozlisit tyto pripady:
        a) odletame ze zakladny
        b) odletame z hvezdy/planety na jinou hvezdu/planetu
        c) odletame z hvezdy/planety do vesmiru
        d) vstupujeme do oblasti hvezdy/planety */

    spaceObject* so  = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
    spaceObject* nso = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectID);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), spaceObjectActuallyIn);
    if (spaceObjectID != 0)
        CHECK_NULL_SPACE_OBJECT_PTR(nso, getID(), spaceObjectID);

    spaceRegularObject* rso  = dynamic_cast<spaceRegularObject*>(so);
    spaceRegularObject* nrso = dynamic_cast<spaceRegularObject*>(nso);

    /* pripad a) */
    if (so->getType() == SOT_BASE)
    {
        if (movementState_ != SMS_STOPPED)
        {
            errLogicalError("Ship [%u] in base, but not stopped", (unsigned long long) getID());
        }
        else
        {
            spaceObjectActuallyIn   = spaceObjectID;
            position                = nrso->getAbsolutePosition() + vector_dist_t(1, 0) * (3 *nrso->getObjectRadius());
            course                  = vector_dbl_t(1.0, 0.0);
            movementState_          = SMS_ORBITING;
        }
        return;
    } 

    /* pripad c) */
    if (spaceObjectID == 0)
    {
        spaceObjectActuallyIn = 0;

        /* uprav pohybovou akci */
        switch (moveAction)
        {
        case SMA_SPACE_OBJECT_ACCELERATE: moveAction = SMA_SPACE_ACCELERATE;     break;
        case SMA_SPACE_OBJECT_NOTHING:    moveAction = SMA_SPACE_NOTHING;        break;
        case SMA_SPACE_OBJECT_STOP:       moveAction = SMA_SPACE_STOP;           break;
        case SMA_SPACE_OBJECT_ORBIT:      moveAction = SMA_SPACE_OBJECT_NOTHING; break;
        } 

        if (movementState_ == SMS_ORBITING)
            movementState_ = SMS_REGULAR;
        return;
    }

    /* pripad b) */
    if (so->getParentSpaceObject() == spaceObjectID)
    {
        spaceObjectActuallyIn = spaceObjectID;
        return;
    }

    /* pripad d) */

    /* nastavime pozici, odkud jsme priletli */
    spaceObjectActuallyIn = spaceObjectID;

    /* pokud pristavame na zakladnu, nastavime pozici na [0,0], vynulujeme rychlost a zrychleni a vypneme motory */
    if (nso->getType() == SOT_BASE)
    {
        position                = vector_dist_t(0, 0);
        speedNorm               = 0;
        acceleration            = 0;
        gravitationSpeedNorm    = 0;
        MovementTurnOffEngine();
        moveAction      = SMA_SPACE_OBJECT_NOTHING;
        movementState_  = SMS_STOPPED;
    }

    /* vynuluj gravitacni rychlost */
    gravitationSpeedNorm = 0;
}

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

void shipClass :: MovementFreeSpaceDoMobilityEvent(void)
{
    /* updatujeme pozici lodi */
    MovementFreeSpaceUpdateShipPosition();

    /* kontrola vstupu do hvezdneho systemu */
    if (MovementFreeSpaceMustEnterStarSystem(position, speedNorm))
    {
        MovementFreeSpaceEnterIntoSolarSystem(nearestStar);
    }
    else
    {
        /* updatujeme napred cile, ktere nastavi akce */
        MovementFreeSpaceUpdateTarget();

        /* updatujeme akci */
        MovementFreeSpaceUpdateAction();

        /* zkontrolujeme eventy */
        MovementFreeSpaceCheckRefreshEvents();
    }
}

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

void shipClass :: MovementSpaceObjectDoMobilityEvent(void)
{
    /* updatujeme pozici lodi */
    MovementSpaceObjectUpdateShipPosition();

    /* kontrola vstupu do hvezdneho systemu */
    dtIdentifier starObjectID;
    if (MovementSpaceObjectMustEnterOtherObject(position, speedNorm, starObjectID))
    {
        MovementSpaceObjectEnterIntoOtherObject(starObjectID);
    }
    else
    {
        /* updatujeme napred cile, ktere nastavi akce */
        MovementSpaceObjectUpdateTarget();

        /* updatujeme akci */
        MovementSpaceObjectUpdateAction();

        /* zkontrolujeme eventy */
        MovementSpaceObjectCheckRefreshEvents();

        /* posleme notifikace lodim v seznamu */
        MovementNotifyOtherPlayers();
    }
}

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

void shipClass :: MovementNotifyOtherPlayers(void)
{
    if (spaceObjectActuallyIn != 0 && !gctx.eng.isClientUpdateSuppressed())
    {
        std :: set<dtIdentifier> players;

        /* projedeme vsechny lode */ 
        spaceIndexItem* itm = actx->spaceObjectIndex.getNearestItem(position);
        if (itm != NULL)
        {

            for (std :: multimap<dtIdentifier, dtIdentifier> :: iterator iter = actx->spaceObjectIndex.getShips().lower_bound(itm->spaceSystemIndex_);
                 iter != actx->spaceObjectIndex.getShips().upper_bound(itm->spaceSystemIndex_); iter++)
            {
                shipClass* c = actx->cacheFortressesList.getItem<shipClass>(iter->second);
                if (c == NULL)
                {
                    /* lod nebyla nalezena - to je chyba */
                    errExceptionError("Ship [%u] not found!", (unsigned long long) iter->second);
                    return;
                }

                /* pokud neni lod v normalnim vesmiru, pokracuj */
                if (!c->MovementIsInNormalSpace())
                    continue;

                /* zarad hrace do seznamu hracu, pokud je lod cizi a v dosahu senzoru */
                if ((c->getFortressRealmID() != getFortressRealmID()) && ((unsigned long long)(position - c->MovementGetShipPosition()).norm() < HRSensorsRange()))
                {
                    players.insert(c->getFortressRealmID());
                }
            }

            /* updatovaci zprava */
            protocolWriter w;
            w.beginMessage(MT_UPDATE, UPDATE_AREA);
            w.writeValue(UPDATE_AREA_STAR_ID, itm->spaceSystemIndex_);
            w.endMessage();

            for (std :: set<dtIdentifier> :: const_iterator iter = players.begin(); iter != players.end(); iter++)
            {
                gctx.sendToClient(id(*iter, actx->index), w.copyMessage());
            }
        }
        else
        {
            errExceptionError("Cannot find nearest star object [%u] for ship [%u]", 
                (unsigned long long)actx->spaceObjectIndex.getNearestItem(position), 
                (unsigned long long)getID());
        }
    }
}

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

vector_dist_t shipClass :: MovementEstimateWarpPosition(void) 
{
    if (MovementIsInWarp())
    {
        const vector_dist_t course      = (warpTarget_ - position).normedVector();
        const dv_time :: datetime dt    = wt2gt(dv_time :: now()) - warpStart_;
        const vector_dist_t pos         = updateWarpPosition(position, course, MovementGetWarpSpeed(), dt); 

        return pos;
    }
    else
    {
        errLogicalError("Trying to estimate warp position at ship %u while not in warp", (unsigned long long)getID());
        return vector_dist_t(0, 0);
    }
}

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

bool shipClass :: MovementSpaceObjectMustEnterOtherObject(const vector_dist_t& pos, 
        const dist_t speed, dtIdentifier& spaceObjectID)
{
    /* pokud je lod v zakladne, nedelej nic */
    if (MovementIsDockedInBase())
        return false;

    /* napred ziskame aktualni space objekt, ve kterem lod je */
    spaceRegularObject* so = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), spaceObjectActuallyIn);
    if (so == NULL)
        return false;

    /* pokud je lod dostatecne vzdalena od stredu objektu, vrat true */
    const dist_t shipFromObjectSquaredDistance  = (pos - so->getAbsolutePosition()).squaredNorm();
    const dist_t areaSquaredSize                = so->getSquaredAreaRadius();
    if (shipFromObjectSquaredDistance > areaSquaredSize)
    {
        spaceObjectID = so->getParentSpaceObject();
        return true;
    }
 

    /* jinak projed vsechny vesmirne objekty, ktere jsou podobjekty tohoto objektu a pokud jsou blizko, otestuj,
       zda chce do nich uzivatel vstoupit */
    for (spaceObject :: dtIdentifierConstIterator iter = so->subObjectsBegin(); iter != so->subObjectsEnd(); iter++)
    {
        spaceObject* mobj = actx->cacheSpaceObjectList.getItem<spaceObject>(*iter);
        CHECK_NULL_SPACE_OBJECT_PTR(mobj, getID(), (*iter));
        if (mobj == NULL) 
            return false;

        /* krome zakladen */
        if (mobj->getType() == SOT_BASE)
            continue;

        spaceRegularObject* cobj = dynamic_cast<spaceRegularObject*>(mobj);
        CHECK_NULL_SPACE_OBJECT_PTR(cobj, getID(), (*iter));
        if (cobj == NULL)
            return false;

        if ((pos - (cobj)->getAbsolutePosition()).squaredNorm() > (cobj)->getSquaredAreaRadius()) 
            continue;
        spaceObjectID = cobj->getID();

        /* pokud chceme vstoupit, vrat true */
        if (wantEnterSpaceObject) 
            return true;

        /* jestlize jsme blize, nez 2x polomer toho objektu, vstup vynucene */
        if ((pos - cobj->getAbsolutePosition()).squaredNorm() <= 2.0L * cobj->getSquaredObjectRadius())
            return true;

        /* jestlize je rychlost prilis nizka, vstup vynucene */
        if (cobj->getOrbitingSpeed(pos) >= speed)
            return true;
    }

    return false;
}

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

vector_dist_t shipClass :: MovementGetShipAbsolutePosition(void)
{
        return position;
}

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

dist_t shipClass :: MovementGetDistanceFrom(const vector_dist_t& pos)
{
    return (dist_t)((MovementGetShipAbsolutePosition() - pos).norm());
}

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

dist_t shipClass :: MovementGetDistanceFrom(dtIdentifier object)
{
	const spaceRegularObject* source = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(object);
    CHECK_NULL_SPACE_OBJECT_PTR(source, getID(), object);
    return (dist_t)((MovementGetShipAbsolutePosition() - source->getAbsolutePosition()).norm());
}

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

dist_t shipClass :: MovementGetMaximalTravelDistanceFrom(const vector_dist_t& pos)
{
    return (dist_t)(PI * (double)MovementGetDistanceFrom(pos));
}

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

dist_t shipClass :: MovementGetMaximalTravelDistanceFrom(dtIdentifier object)
{
    return (dist_t)(PI * (double)MovementGetDistanceFrom(object));
}

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

void shipClass :: MovementFreeSpaceUpdateTarget(void)
{
    if (movementState_ == SMS_ORBITING)
    {
        errLogicalError("Orbiting in free space, ship [%u]", (unsigned long long)getID());
        return;
    }
    if (movementState_ == SMS_WARP)
        return;

    switch (moveTarget)
    {
    case SMT_MOVE_TO_SPACE_OBJECT:
        {
            /* doletneme ke hvezde, jejiz hvezdna soustava obsahuje dany objekt */
            dtIdentifier star    = spaceObjectGetStarSystem(targetSpaceObject);
            wantEnterSpaceObject = nearestStar == targetSpaceObject;

            /* nastavime kurz k te hvezde */
			spaceObject* so      = actx->cacheSpaceObjectList.getItem<spaceObject>(star);
            CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), star);
            if (so->getAbsolutePosition() != position)
            {
                MovementFreeSpaceChangeCourse(convert_vec<double, dist_t>((so->getAbsolutePosition() - position)).normedVector());
                moveAction = SMA_SPACE_ACCELERATE;
            }
            else
            {
                /* zastavime */
                moveAction = SMA_SPACE_STOP;
            }
            
            break;
        }
    case SMT_MOVE_TO_POSITION:
        {
            /* doletneme na danou pozici */
            if ((targetPosition - position).norm() < MOVEMENT_POS_LIMIT) 
            {
                moveAction = SMA_SPACE_STOP;
            }
            else
            {
                MovementFreeSpaceChangeCourse(convert_vec<double, dist_t>((targetPosition - position)).normedVector());
                moveAction = SMA_SPACE_ACCELERATE;
            }

            break;
        }
    case SMT_ORBIT:
        errLogicalError("Trying to orbit in free space with ship [%u]", (unsigned long long) getID());
        break;
    case SMT_STOP:
        /* pouze dame akci, ze zastavime */
        moveAction = SMA_SPACE_STOP;
        break;
    case SMT_NONE:
        /* u tohoto targetu nedelej nic */
        break;
    case SMT_MOVE_TO_SHIP:
        {
        /* napred zjistime, zda lod vubec existuje */
        shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(targetShip);
        if (shp != NULL)
        {
            vector_dist_t targetPosition = shp->MovementGetShipPosition();

            if ((targetPosition - position).squaredNorm() < MOVEMENT_POS_LIMIT)
            {
                if (MovementFreeSpaceChangeCourse(shp->course, false))
                {
                    dist_t targetSpeed = shp->MovementGetCurrentSpeed();

                    if (targetSpeed > MovementGetCurrentSpeed())
                    {
                        moveAction = SMA_SPACE_ACCELERATE;
                    }
                    else
                        if (targetSpeed < MovementGetCurrentSpeed())
                        {
                            moveAction = SMA_SPACE_NOTHING;
                            speedNorm  = (dist_t)slowShip((unsigned long long)speedNorm, (unsigned long long)targetSpeed);
                        }
                }
            }
            else
            {
                MovementSpaceObjectChangeCourse(convert_vec<double, dist_t>((targetPosition - position)).normedVector());
                moveAction = SMA_SPACE_ACCELERATE;
            }
        }

        }
        break;
    default:
        errLogicalError("Unknown target type (%u) in ship [%u]", (unsigned long long) moveTarget, (unsigned long long) getID());
    }
}

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

bool shipClass :: MovementLand(dtIdentifier base)
{
	/* PRACE PRO JAKUBA */
	/* nic neoverovat, neresit palivo, motory, ani nic dalsiho */
	/* jen lod zastavit a ulozit do baze v parametru, tedy zejmena nastavit spaceObjectActuallyIn */
	/* z toho i plyne, ze by to melo vzdy vracet true, nebo by to mohlo byt void */

    baseClass* basePtr = actx->cacheFortressesList.getItem<baseClass>(base);
    if (basePtr != NULL)
    {
        /* vypneme motory */
        fireOutImpulsJetEngine(0);

        /* nastavime parametry lodi */
        speedNorm               =   0;
        acceleration            =   0;
        gravitationSpeedNorm    =   0;
        spaceObjectActuallyIn   =   basePtr->getFortressSpaceObjectHolder()->getID();
        movementState_          =   SMS_STOPPED;

        moveAction              =   SMA_SPACE_OBJECT_STOP;
        moveTarget              =   SMT_STOP;

        return true;
    }
    else
    {
        errLogicalError("Base %u does not exist!", (unsigned long long)base);
        return false;
    }

    return false;
}

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

bool shipClass :: MovementTakeOff(void)
{
    spaceFortressObject* obj  = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectActuallyIn);
    spaceRegularObject*  robj = dynamic_cast<spaceRegularObject*>(obj->getParentSpaceObjectInstance());
    
    if (obj != NULL && robj != NULL)
    {
        position                = robj->getAbsolutePosition();
        position.x              = position.x + robj->getAreaRadius() * 0.5L;
        spaceObjectActuallyIn   = robj->getID();
        MovementSpaceObjectActionOrbit();
        MovementTargetOrbit();        

        return true;
    }
    else
    {
        return false;
    }
}

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

void shipClass :: MovementSpaceObjectUpdateTarget(void)
{
    if (movementState_ == SMS_WARP)
        return;

    switch (moveTarget)
    {
    case SMT_MOVE_TO_SPACE_OBJECT:
        {
            spaceObject* tobj = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
            CHECK_NULL_SPACE_OBJECT_PTR(tobj, getID(), targetSpaceObject);
            if (tobj == NULL) break;

            /* pokud uz jsme v objektu, nic nedelame */
            if (spaceObjectActuallyIn == targetSpaceObject)
            {
                if (tobj->getType() == SOT_BASE)
                {
                    MovementSpaceObjectActionStop();
                }
                else
                {
                    // zkusime, jestli jsme v kruznici, v tom pripade zacneme obihat, jinak letime dal smerem k centru oblasti
                    dist_t gcRadius = MovementSpaceObjectGetGravitationCircleRadius(speedNorm);
                    if (gcRadius < (position - tobj->getAbsolutePosition()).norm())
                    {
                        // letime k centru
                        MovementSpaceObjectChangeCourse(convert_vec<double, dist_t>((tobj->getAbsolutePosition() - position)).normedVector(), false);
                        MovementSpaceObjectActionAccelerate();
                    }
                    else
                    {
                        // zacneme obihat 
                        if (movementState_ != SMS_ORBITING)
                        {
                            MovementSpaceObjectActionOrbit();
                        }
                    }
                }
            }
            else 
            {
                if (tobj->getType() == SOT_BASE)
                {
                    /* letime k zakladne */
                    spaceFortressObject* base = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(targetSpaceObject);
                    CHECK_NULL_SPACE_OBJECT_PTR(base, getID(), targetSpaceObject);
                    if (base == NULL) break;

                    /* najdeme si jeji planetu */
                    spaceRegularObject* planet = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(base->getParentSpaceObject());
                    CHECK_NULL_SPACE_OBJECT_PTR(planet, getID(), base->getParentSpaceObject());
                    if (planet == NULL) break;

                    /* jestlize jsme u teto planety, pristaneme */
                    if (planet->getID() == spaceObjectActuallyIn)
                    {
                        if (dockDown(actx->cacheFortressesList.getItem<baseClass>(base->getFortressID())) == DR_OK)
                        {
                            moveTarget = SMT_NONE;
                        }
                    }
                    else
                    {
                        /* letime k teto planete */
                        MovementSpaceObjectActionMoveTo(planet->getAbsolutePosition());
                    }
                }
                else
                {
                    /* neletime k zakladne */
					spaceObject* target = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
                    CHECK_NULL_SPACE_OBJECT_PTR(target, getID(), targetSpaceObject);
                    if (target == NULL) break;
                    
                    MovementSpaceObjectActionMoveTo(target->getAbsolutePosition());
                }
            }
            
            break;
        }
    case SMT_MOVE_TO_POSITION:
        {
            /* doletneme na danou pozici */
            const vector_dist_t cpos  = position;

            if (position != targetPosition)
                MovementSpaceObjectActionMoveTo(targetPosition);
            else
            {
                MovementSpaceObjectActionStop();
                moveTarget = SMT_STOP;
            }

            break;
        }
    case SMT_ORBIT:
        if (movementState_ != SMS_ORBITING)
        {
            MovementSpaceObjectBeginOrbit();
        }
        break;
    case SMT_STOP:
        /* pouze dame akci, ze zastavime */
        MovementSpaceObjectActionStop();
        break;
    case SMT_NONE:
        /* u tohoto targetu nedelej nic */
        break;
    case SMT_MOVE_TO_SHIP:
        {
        /* napred zjistime, zda lod vubec existuje */
        shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(targetShip);
        if (shp != NULL)
        {
            /* lod nesmi byt ve warpu */
            if (!shp->MovementIsInWarp())
            {
                vector_dist_t shipPosition = shp->MovementGetShipPosition();
                if ((shipPosition - position).squaredNorm() < MOVEMENT_POS_LIMIT)
                {
                    if (shp->MovementIsOrbiting())
                    {
                        if (movementState_ != SMS_ORBITING)
                            MovementSpaceObjectBeginOrbit();
                    }
                    else
                    {
                        if (MovementSpaceObjectChangeCourse(shp->course, false))
                        {
                            dist_t targetSpeed = shp->MovementGetCurrentSpeed();

                            if (targetSpeed > MovementGetCurrentSpeed())
                            {
                                MovementSpaceObjectActionAccelerate();
                            }
                            else
                                if (targetSpeed < MovementGetCurrentSpeed())
                                {                                    
                                    speedNorm  = (dist_t)slowShip((unsigned long long)speedNorm, (unsigned long long)targetSpeed);
                                    MovementSpaceObjectActionStopAccelerating();
                                }
                        }
                    }
                }
                else
                {
                    MovementSpaceObjectActionMoveTo(shipPosition);
                }
            }
            else
            {
                if (movementState_ != SMS_ORBITING)
                {
                    if (!MovementSpaceObjectBeginOrbit())
                        MovementSpaceObjectActionStop();
                }
            }
        }

        }
        break;
    default:
        errLogicalError("Unknown target type (%u) in ship [%u]", (unsigned long long) moveTarget, (unsigned long long) getID());
    }
}

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

void shipClass :: MovementSpaceObjectActionStopAccelerating(void)
{
    stopAllQuarryingIfQuarryingSomething();
    MovementTurnOffEngine();
    acceleration = 0;
    movementState_ = SMS_REGULAR;
}

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

void shipClass :: MovementSpaceObjectActionMoveTo(const vector_dist_t pos)
{
    stopAllQuarryingIfQuarryingSomething();

    spaceObject* sobj = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(sobj, getID(), spaceObjectActuallyIn);
    if (sobj == NULL) return;

    const vector_dist_t     objPos                  = sobj->getAbsolutePosition();
    const dist_t            gcRadius                = MovementSpaceObjectGetGravitationCircleRadius(speedNorm);
    const dist_t            distanceGCvsTarget      = (pos - objPos).norm();
    const dist_t            distanceGCvsShip        = (position - objPos).norm();
    const vector_dist_t     newCourse               = (pos - position).normedVector();
    const vector_dist_t     courseToObj             = (objPos - position).normedVector();
    const dist_t            cosOfAngle              = newCourse * courseToObj;

    // rozlisime pripad, kdy je cil vevnitr kruznice a venku
    if (gcRadius > distanceGCvsTarget)
    {
        if (MovementSpaceObjectChangeCourse(newCourse, false))
            MovementSpaceObjectActionAccelerate();
        else
            MovementSpaceObjectActionStopAccelerating();
    }
    else
    {
        if (MovementIsOrbiting())
        {
            // zjistime, jestli kurz neprotina kruznici
            if (cosOfAngle < 0)
            {
                // neprotina, jde mimo
                if (MovementSpaceObjectChangeCourse(newCourse, false))
                    MovementSpaceObjectActionAccelerate();
            }
            else
            {
                // protina, nedelame nic
            }
        }
        else
        {
            // neni na orbite, pouze nastavime kurz       
            if (MovementSpaceObjectChangeCourse(newCourse, false))
                MovementSpaceObjectActionAccelerate();
            else
                MovementSpaceObjectActionStopAccelerating();
        }
    }
}

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

void shipClass :: MovementSpaceObjectActionAccelerate(void)
{
    stopAllQuarryingIfQuarryingSomething();

    acceleration = MovementTurnOnEngine();
    if (acceleration != 0)
    {
        if (movementState_ == SMS_ORBITING)
            stopAllQuarryingIfQuarryingSomething();
        movementState_ = SMS_REGULAR;
    }
}

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

void shipClass :: MovementSpaceObjectActionOrbit(void)
{
    if (movementState_ == SMS_ORBITING)
        errLogicalError("Trying to begin orbiting while orbiting - ship [%u]", (unsigned long long) getID());
  
    spaceRegularObject* so = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), spaceObjectActuallyIn);
    dist_t speed    = so->getOrbitingSpeed(position);

    movementState_          = SMS_ORBITING;
    speedNorm               = speed;
    gravitationSpeedNorm    = 0;
}

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

void shipClass :: MovementSpaceObjectActionStop(void)
{
    MovementTurnOffEngine();
    
    stopAllQuarryingIfQuarryingSomething();

    dist_t newspeed = speedNorm;
    if (speedNorm != 0)
        newspeed = (dist_t)slowShip((unsigned long long) speedNorm, 0);

    if (newspeed == 0)
    {
        speedNorm = 0;
        acceleration = 0;
        gravitationSpeedNorm = 0;
        
        movementState_ = SMS_STOPPED;
    }
    else 
    {
        speedNorm = (double)newspeed;
        acceleration = 0;
        movementState_ = SMS_REGULAR;
    }
}

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

dist_t shipClass :: MovementSpaceObjectGetGravitationCircleRadius(dist_t speed)
{
    spaceRegularObject* tobj = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(tobj, getID(), spaceObjectActuallyIn);
    if (tobj == NULL) 
        return numeric_limits<dist_t> :: quiet_NaN();
    else
        return max(min(computeGravitationCircleRadius(tobj->getWeight(), speed), tobj->getAreaRadius()), tobj->getObjectRadius() * 2.0L);
}

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

void shipClass :: MovementFreeSpaceUpdateAction(void)
{
    if (movementState_ == SMS_WARP)
        return;

    switch (moveAction)
    {
    case SMA_SPACE_NOTHING:
        acceleration = 0;
        MovementTurnOffEngine();
        movementState_ = speedNorm != 0 ? SMS_REGULAR : SMS_STOPPED;
        break;
    case SMA_SPACE_ACCELERATE:
        acceleration = MovementTurnOnEngine();
        movementState_ = SMS_REGULAR;
        break;
    case SMA_SPACE_STOP:
        /* pokud muzeme, zastavime okamzite */
        {
            MovementTurnOffEngine();
            unsigned long long newspeed = slowShip((unsigned long long) speedNorm, 0);


            if (newspeed == 0)
            {
                speedNorm               = 0;
                acceleration            = 0;
                gravitationSpeedNorm    = 0;
                
                movementState_ = SMS_STOPPED;
            }
            else 
            {
                speedNorm = (double)newspeed;
                acceleration = 0;
                movementState_ = SMS_REGULAR;
            }
        }
        break;
    }
}

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

void shipClass :: MovementSpaceObjectUpdateAction(void)
{
#if 0
    if (movementState_ == SMS_WARP)
        return;

    spaceObject* soin = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(soin, getID(), spaceObjectActuallyIn);
    if (soin == NULL) return;

    /* pokud jsme na zakladne, budto zvletneme, nebo nedelame nic */
    if (soin->getType() == SOT_BASE)
    {
        if (moveAction != SMA_SPACE_OBJECT_STOP && moveAction != SMA_SPACE_OBJECT_NOTHING)
        {
            MovementTakeOff();
        }
    }

    switch (moveAction)
    {
    case SMA_SPACE_OBJECT_NOTHING:
        acceleration = 0;
        MovementTurnOffEngine();
        if (movementState_ == SMS_ORBITING)
            stopAllQuarrying();
        movementState_ = speedNorm != 0 || gravitationSpeedNorm != 0 ? SMS_REGULAR : SMS_STOPPED;
        break;
    case SMA_SPACE_OBJECT_ACCELERATE:
        acceleration = MovementTurnOnEngine();
        if (movementState_ == SMS_ORBITING)
            stopAllQuarrying();
        movementState_ = SMS_REGULAR;
        break;
    case SMA_SPACE_OBJECT_STOP:
        /* pokud muzeme, zastavime okamzite */
        {
            MovementTurnOffEngine();

            if (movementState_ == SMS_ORBITING)
                stopAllQuarrying();
            dist_t newspeed = speedNorm;
            if (speedNorm != 0)
                newspeed = (dist_t)slowShip((unsigned long long) speedNorm, 0);

            if (newspeed == 0)
            {
                speedNorm = 0;
                acceleration = 0;
                gravitationSpeedNorm = 0;
                
                movementState_ = SMS_STOPPED;
            }
            else 
            {
                speedNorm = (double)newspeed;
                acceleration = 0;
                movementState_ = SMS_REGULAR;
            }
        }
        break;
    case SMA_SPACE_OBJECT_ORBIT:
       if (movementState_ != SMS_ORBITING)
            MovementSpaceObjectBeginOrbit();
        break;
    default:
        errExceptionError("Bad move action (%u) at ship [%u]", (unsigned long long) moveAction, (unsigned long long) getID()); 
    }
#endif
}

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

void shipClass :: DoMobilityEvent(void)
{
    MovementUpdateShipMovementStatus();

    /* posleme oznameni o updatu klientovi */
    protocolWriter w;
    w.beginMessage(MT_UPDATE, UPDATE_SHIP);
    w.writeValue(UPDATE_SHIP_ID, getID());
    w.endMessage(true);

    gctx.sendToClient( make_pair(getFortressRealmID(), actx->index), w.copyMessage() );
}

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

void shipClass :: MovementUpdateShipMovementStatus(void)
{
    if (!isMovementUpdatedTEMP_)
    {
        isMovementUpdatedTEMP_ = true;
        if (spaceObjectActuallyIn == 0)
        {
            /* jsme ve volnem vesmiru */
            MovementFreeSpaceDoMobilityEvent();
        } else
        {
            MovementSpaceObjectDoMobilityEvent();
        }
        isMovementUpdatedTEMP_ = false;
    }
}

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

void shipClass :: MovementSpaceObjectEndOrbit(void)
{
    if (movementState_ != SMS_ORBITING)
        errLogicalError("Trying to end orbiting while not orbiting - ship [%u]", (unsigned long long) getID());
    stopAllQuarrying();
    MovementSpaceObjectUpdateShipPosition();
    movementState_ = SMS_REGULAR;
    MovementSpaceObjectUpdateShipPosition();
}

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

bool shipClass :: MovementSpaceObjectIsOutsideOfGC(const vector_dist_t pos, const dist_t speed)
{
    /* vezmeme nasi hvezdu */
    spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);
    if (star == NULL)
        return false;     

    return MovementSpaceObjectGetGravitationCircleRadius(speed) < (pos - star->getAbsolutePosition()).norm();
}

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

bool shipClass :: MovementSpaceObjectBeginOrbit(void)
{
    if (movementState_ == SMS_ORBITING)
        errLogicalError("Trying to begin orbiting while orbiting - ship [%u]", (unsigned long long) getID());

    spaceRegularObject* so = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
    CHECK_NULL_SPACE_OBJECT_PTR(so, getID(), spaceObjectActuallyIn);
    if (so == NULL)
        return false;

    dist_t speed    = so->getOrbitingSpeed(position);
    dist_t dspeed   = speedNorm - speed;
    if (dspeed > 0)
    {
        if (MovementTurnEnginesForDecreaseSpeed(dspeed))
        {
            movementState_          = SMS_ORBITING;
            speedNorm               = speed;
            gravitationSpeedNorm    = 0;
            return true;
        }
    }
    else
    {
        if (hangShipToOrbit((unsigned long long)speedNorm, (unsigned long long)speed))
        {
            movementState_          = SMS_ORBITING;
            speedNorm               = speed;
            gravitationSpeedNorm    = 0;
            return true;
        }
    }

    return false;
}

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

vector_dist_t shipClass :: MovementGetShipPosition(bool updatePosition)
{
    /* update pozice lodi */
    if (updatePosition)
    {
        MovementUpdateShipMovementStatus();
    }

    return position;
}

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

bool shipClass :: MovementWarpTravel(const vector_dist_t targetPos)
{
    /* update pozice lodi */
    if (spaceObjectActuallyIn == 0)
    {
        MovementFreeSpaceUpdateShipPosition();
    }
    else
    {
        MovementSpaceObjectUpdateShipPosition();
    }

    if (movementState_ != SMS_WARP && !MovementIsDockedInBase())
    {
        if (MovementTurnOnWarpEngine())
        {
            stopAllQuarryingIfQuarryingSomething();

            MovementTurnOffEngine();
            acceleration            = 0;
            speedNorm               = 0;
            gravitationSpeedNorm    = 0;

            warpTarget_             = targetPos;
            warpStart_              = wt2gt(dv_time:: now());
            movementState_          = SMS_WARP;

            /* estimate warp end and check event */
            dist_t distance         = (position - targetPos).norm();
            dv_time:: datetime    d = computeTimeForTravelDistance(distance, MovementGetWarpSpeed());
            MovementCheckMobilityEvent(warpStart_ + d);

            WarpInfo w;
            vector_dist_t cposEst   = MovementEstimateWarpPosition();
            w.dstPosX               = targetPos.x;
            w.dstPosY               = targetPos.y;
            w.posX                  = cposEst.x;
            w.posY                  = cposEst.y;
            w.sposX                 = position.x;
            w.sposY                 = position.y;
            w.inWarp                = true;
            w.shipId                = getID();
            w.stateChange           = true;
            w.speed                 = MovementGetWarpSpeed();

            gctx.sendToClient(make_pair(getFortressRealmID(), actx->index), answerWriter :: ship_warp_information(w));

            return true;
        }

        return false;
    }
    else
    {
        errLogicalError("Cannot activate warp - bad movement state at ship [%u]", (unsigned long long) getID());
        return false;
    }
}

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

void shipClass :: MovementAfterWarpEmergencyShutdown(void)
{
    if (movementState_ == SMS_WARP)
    {   
        dv_time:: datetime delta =  wt2gt(dv_time::now()) - warpStart_;
        dist_t range = computeTravelledDistance(MovementGetWarpSpeed(), delta);

        position = position + vector_dist_t((dist_t)(2.0L*rand01()*(double)range - range), 
            (dist_t)(2.0L*rand01()*(double)range - range));

        movementState_ = SMS_STOPPED;
        MovementTurnOffWarpEngine();

        MovementUpdateShipMovementStatus();
    }
    else
    {
        errLogicalError("Cannot deactivate warp - bad movement state at ship [%u]", (unsigned long long) getID());
        return;
    }
}

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

void shipClass :: MovementSetEngineIgnitionLimit(const dv_time:: datetime delta)
{
    engineLimit_ = wt2gt(dv_time:: now()) + delta;
}

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

void shipClass :: MovementTargetStopShip(void)
{
    moveTarget = SMT_STOP;
    MovementUpdateShipMovementStatus();
}

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

void shipClass :: MovementTargetMoveTo(const dist_t x, const dist_t y)
{
    MovementUpdateShipMovementStatus();
    targetPosition = vector_dist_t(x, y);
    moveTarget     = SMT_MOVE_TO_POSITION;
    MovementUpdateShipMovementStatus();
}

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

bool shipClass :: MovementTargetOrbit(void)
{
    if (!(MovementIsDockedInBase() || (spaceObjectActuallyIn == 0) || MovementIsInWarp()))
    {
        moveTarget     = SMT_ORBIT;
        MovementUpdateShipMovementStatus();
        return true;
    }
    return false;
}

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

bool shipClass :: MovementTargetPursuit(unsigned long otherShipID)
{
    if (! (MovementIsDockedInBase() || MovementIsInWarp()) )
    {
        targetShip = otherShipID;
        moveTarget = SMT_MOVE_TO_SHIP;
        MovementUpdateShipMovementStatus();
        return true;
    }

    return false;
}

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

bool shipClass :: MovementTargetMoveToSpaceObject(unsigned long spaceObject)
{
    if (! (MovementIsDockedInBase() || MovementIsInWarp()) )
    {
        targetSpaceObject = spaceObject;
        moveTarget = SMT_MOVE_TO_SPACE_OBJECT;
        MovementUpdateShipMovementStatus();
        return true;
    }

    return false;
}

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

bool shipClass :: MovementIsDockedInBase(void)
{
    if (spaceObjectActuallyIn != 0)
    {
        spaceObject* obj = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(obj, getID(), spaceObjectActuallyIn);
        if (obj != NULL)
		{
            return obj->getType() == SOT_BASE;
		}
    }
    return false;
}

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

void shipClass :: MovementCheckMobilityEvent(dv_time:: datetime ev)
{    
    gctx.eng.registerEvent(ev, new shipMovementUpdate(ev, getID()), shipMovementTriggerIdentificator_);
}

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

dtIdentifier shipClass :: MovementGetTargetShip(void) const
{
    return targetShip;
}

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

void shipClass :: UpdateEvents()
{
    fortressClass :: UpdateEvents();

    shipMovementTriggerIdentificator_ = 0;
    MovementUpdateShipMovementStatus();
}

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

dtIdentifier shipClass :: MovementGetTargetSpaceObject(void) const
{
    return targetSpaceObject;
}

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

vector_dist_t shipClass :: MovementGetTargetPosition(void) const
{
    return targetPosition;
}

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

dist_t shipClass :: MovementEstimationDistance(void) const
{
    switch (moveTarget)
    {
    case SMT_MOVE_TO_SPACE_OBJECT:      
        {
            spaceObject* tobj = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
            CHECK_NULL_SPACE_OBJECT_PTR(tobj, getID(), spaceObjectActuallyIn);
            if (tobj == NULL) break;

            /* pokud uz jsme v objektu, nic nedelame */
            if (spaceObjectActuallyIn == targetSpaceObject)
            {
                return 0;
            }
            else 
            {
                if (tobj->getType() == SOT_BASE)
                {
                    /* letime k zakladne */
                    spaceFortressObject* base = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(targetSpaceObject);
                    CHECK_NULL_SPACE_OBJECT_PTR(base, getID(), targetSpaceObject);
                    if (base == NULL) break;

                    /* najdeme si jeji planetu */
                    spaceRegularObject* planet = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(base->getParentSpaceObject());
                    CHECK_NULL_SPACE_OBJECT_PTR(planet, getID(), base->getParentSpaceObject());
                    if (planet == NULL) break;

                    /* jestlize jsme u teto planety, vratime nulu */
                    if (planet->getID() == spaceObjectActuallyIn)
                    {
                        return 0;
                    }
                    else
                    {
                        /* zmerime vzdalenost k tomuto vesmirnemu objektu */
                        return (position - planet->getAbsolutePosition()).norm();
                    }
                }
                else
                {
                    /* neletime k zakladne */
					spaceObject* target = actx->cacheSpaceObjectList.getItem<spaceObject>(targetSpaceObject);
                    CHECK_NULL_SPACE_OBJECT_PTR(target, getID(), targetSpaceObject);
                    if (target == NULL) break;
                    
                    /* zmerime vzdalenost k tomuto vesmirnemu objektu */
                    return (position - target->getAbsolutePosition()).norm();
                }
            }
        }        
        
        
        return 0;
    case SMT_MOVE_TO_POSITION:          return MovementIsInWarp() ? (position - warpTarget_).norm() : 
                                            (position - targetPosition).norm();
    case SMT_ORBIT:                     return 0;
    case SMT_NONE:                      return 0;
    case SMT_MOVE_TO_SHIP:   
        {
        /* napred zjistime, zda lod vubec existuje */
        shipClass* shp = actx->cacheFortressesList.getItem<shipClass>(targetShip);
        if (shp != NULL && !MovementIsInWarp())
        {
            /* lod nesmi byt ve warpu */
            if (!shp->MovementIsInWarp())
            {
                vector_dist_t targetPosition = shp->MovementGetShipPosition();
                return (targetPosition - position).norm();
            }
        }        
        }
        return 0;
    case SMT_STOP:                      return 0;
    default:
        errExceptionError("Invalid target state %u at ship [%u]", (unsigned long long)moveTarget, (unsigned long long) getID());
        return 0;
    }

    return 0;
}

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

dv_time:: datetime shipClass :: MovementEstimationTime(const dist_t travel_distance) 
{
    if (MovementIsInWarp())
    {
        dist_t speed = MovementGetWarpSpeed();
        if (speed == 0)
        {
            errLogicalError("Warp speed is zero at the ship [%u]", (unsigned long long) getID());
        }
        else
        {
            return computeTimeForTravelDistance(travel_distance, speed);
        }
    }
    else
    {
        const dist_t v = speedNorm;
        const dist_t a = acceleration;

        if (v == 0 && a == 0) 
            return 0.0L;

        return computeTimeForTravelDistance(travel_distance, v, a);
    }

    return 0.0L;
}

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

const char* movementStateToStr(const shipMovementState sms)
{
    switch (sms)
    {
    case SMS_REGULAR:       return REQUEST_SHIP_JOURNEY_ANSWER_SMS_REGULAR;
    case SMS_ORBITING:      return REQUEST_SHIP_JOURNEY_ANSWER_SMS_ORBITING;
    case SMS_WARP:          return REQUEST_SHIP_JOURNEY_ANSWER_SMS_WARP;
    case SMS_STOPPED:       return REQUEST_SHIP_JOURNEY_ANSWER_SMS_STOPPED;
    default:
        return "ERROR";
    }
}

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

const char* movementTargetToStr(const shipMoveTarget smt)
{
    switch (smt)
    {
    case SMT_MOVE_TO_SPACE_OBJECT:      return REQUEST_SHIP_JOURNEY_ANSWER_SMT_MOVE_TO_SPACE_OBJECT;
    case SMT_MOVE_TO_POSITION:          return REQUEST_SHIP_JOURNEY_ANSWER_SMT_MOVE_TO_POSITION;
    case SMT_ORBIT:                     return REQUEST_SHIP_JOURNEY_ANSWER_SMT_ORBIT;
    case SMT_NONE:                      return REQUEST_SHIP_JOURNEY_ANSWER_SMT_NONE;
    case SMT_MOVE_TO_SHIP:              return REQUEST_SHIP_JOURNEY_ANSWER_SMT_MOVE_TO_SHIP;
    case SMT_STOP:                      return REQUEST_SHIP_JOURNEY_ANSWER_SMT_STOP;
    default:
        return "ERROR";
    }
}

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

bool shipClass :: MovementTurnEnginesForChangeCourse(double angleRatio)
{
    return turnShip((unsigned long long)speedNorm, (unsigned short)(angleRatio*180));
}

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

bool shipClass :: MovementTurnEnginesForDecreaseSpeed(dist_t speed)
{
    if (speedNorm < speed)
        return true;
    else
    {
        speedNorm = (dist_t)slowShip((unsigned long long)speedNorm, (unsigned long long)speed);
        return speedNorm == speed;
    }
}

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

bool shipClass :: MovementTurnOnWarpEngine(void)
{
#if defined(DONT_USE_FAKE_WARP)
    return switchToWarp();
#else
    return true;
#endif
}

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

void shipClass :: MovementTurnOffWarpEngine(void)
{
#if defined(DONT_USE_FAKE_WARP)
    jumpOutOfWarp(0);
#endif
}

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

vector_dbl_t shipClass :: MovementGetCourse(void) const
{
    return course;
}

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

bool shipClass :: MovementGetOrbitingPivot(vector_dist_t& pivot)
{
    if (MovementIsOrbiting())
    {
        spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);
        if (star == NULL) return false;

        pivot = star->getAbsolutePosition();

        return true;
    }
    else
        return false;
}

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

bool shipClass :: MovementGetAngularSpeed(dist_t& angular_velocity)
{
    if (MovementIsOrbiting())
    {
        spaceRegularObject* star    = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectActuallyIn);
        CHECK_NULL_SPACE_OBJECT_PTR(star, getID(), spaceObjectActuallyIn);
        if (star == NULL) return false;


        angular_velocity     = computeAngularVelocity((position - star->getAbsolutePosition()).norm(), star->getWeight());

        return true;
    }
    else
        return false;
}

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

void shipClass :: MovementUpdateNearestStar(void)
{
    if (MovementIsDockedInBase())
    {
        spaceFortressObject* fobj = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectActuallyIn);
        if (fobj != NULL)
        {
            vector_dist_t p = fobj->getAbsolutePosition();
            spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(p);
            if (ns == NULL)
            {
                errLogicalError("Cannot find nearest star for position [%u, %u]!", (unsigned long long)p.x, (unsigned long long)p.y);
            }
            else
            {
                nearestStar = ns->spaceSystemIndex_;
            }
        }
        else
        {
            errLogicalError("Fortress holder object %u is NULL !", (unsigned long long)spaceObjectActuallyIn);
        }
    }
    else
    {
        if (!MovementIsInWarp())
        {
            spaceIndexItem* ns = actx->spaceObjectIndex.getNearestItem(position);
            if (ns == NULL)
            {
                errLogicalError("Cannot find nearest star for position [%u, %u]!", (unsigned long long)position.x, (unsigned long long)position.y);
            }
            else
            {
                nearestStar = ns->spaceSystemIndex_;
            }
        }
    }
}

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

unsigned long long fortressClass :: LRSensorsRange(void) /* km */
{
    return (unsigned long long)(sensors.longRangeSensors()->actualRange());
}

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

unsigned long long fortressClass :: HRSensorsRange(void) /* km */
{
    return (unsigned long long)(sensors.highResolutionSensors()->actualRange());
}

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

dist_t shipClass :: MovementGetWarpSpeed(void) /* m/sec */
{
#if defined(DONT_USE_FAKE_WARP)
    return (dist_t) unitsConversion<double> :: speedCtoSpeedMS(subspaceDrive.actualSpeedToC());
#else
    return physicsConstants<dist_t> :: lightSpeed();
#endif
}

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

dist_t shipClass :: MovementTurnOnEngine(void)
{
#if defined(DONT_USE_FAKE_ENGINES)
    /* zjistime, jestli muzeme zapnout motory, jinak je vypneme */
    if (wt2gt(dv_time:: now()) > engineLimit_)
    {
        fireOutImpulsJetEngine(0);
        return 0;
    }
    else
    {
        /* zkusime, zda lze zazehnout motory */
        if (fullIgniteImpulsJetEngine())
        {
            unsigned long long force  = impulsDrive.getActualJetForce();
            unsigned long long weight = fortressTotalWeightWithPayload(0, 1);
            return min(computeAcceleration((double)force, (double)weight), impulsDrive.mechanicalDampers()->actualMaxAcceleration());
        }
        else
        {
            fireOutImpulsJetEngine(0);
            return 0;
        }
    }
#else
    if (wt2gt(dv_time:: now()) > engineLimit_)
        return 0; 
    else
    
        return 20000;
#endif
}

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

void shipClass :: MovementTurnOffEngine(void)
{
    fireOutImpulsJetEngine(0);
}

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

bool shipClass :: MovementTurnOnEngineForGravityAnnulating(dist_t g)
{
    return partitialIgniteImpulsJetEngine((unsigned long long)computeForceFromAcceleration(g, (double)fortressTotalCargoWeight(0, 1)+getWeight()));
}

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

dist_t shipClass :: getDistanceFromSpaceObject(dtIdentifier spaceObjectID)
{
    MovementUpdateShipMovementStatus();

    if (MovementIsDockedInBase())
    {
        // lod je na zakladne
        spaceFortressObject* ft = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectActuallyIn);
        spaceObject* ot         = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectID);
        return (ot->getAbsolutePosition() - ft->getAbsolutePosition()).norm();
    }
    else
    {
        if (MovementIsInWarp())
        {
            return std :: numeric_limits<dist_t> :: infinity();
        }
        else
        {
            // lod je v normalnim vesmiru
            spaceObject* ot = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectID);
            return (position - ot->getAbsolutePosition()).norm();
        }
    }
}

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

bool shipClass :: getActualPosition(vector_dist_t& result)
{
    MovementUpdateShipMovementStatus();

    if (MovementIsDockedInBase())
    {
        // lod je na zakladne
        spaceFortressObject* ft = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectActuallyIn);
        result = ft->getAbsolutePosition();
        return true;
    }
    else
    {
        if (MovementIsInWarp())
        {
            return false;
        }
        else
        {
            // lod je v normalnim vesmiru
            result = position;
            return true;
        }
    }
}

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

void shipClass :: beforeDelete()
{
    actx->spaceObjectIndex.removeShip(getID(), nearestStar);

}

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

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


bool baseClass::isConstructed(bool readOnly)
{
	if (readOnly)
	{
		return this->buildingPoints_ == this->weight_;
	}
	else
	{
		if (this->buildingPoints_ == this->weight_)
		{
			return 1;
		}
		else
		{
			return this->actualBuildingPoints() == this->weight_;
		}
	}
};

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

bool baseClass::isThereSomeAblePlanetToBuildAShell(spacePlanetObject ** buildingPlanet)
{
	if (this->isShell(0))
	{
		if (buildingPlanet)
		{
			(*buildingPlanet) = NULL;
		}
		return 0;
	}

	if (buildingPlanet)
	{
		(*buildingPlanet) = this->getFortressPlanet();
	}
	return 1;
};

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

unsigned long long baseClass::maxAndroidsShellCanAccept(androidsClass * androids)
{
	if ((!(this->isShell(0))) || (!androids))
	{
		return 0;
	}

	unsigned long long maxWeightCount = (unsigned long long)((double)(this->loadingWeightLimit()  ) * (double)(SHELL_ANDROIDS_LOADING_LIMIT) / (double)(androids->getWeight()));
	unsigned long long maxSizeCount   = (unsigned long long)((double)(this->loadingCapacityLimit()) * (double)(SHELL_ANDROIDS_LOADING_LIMIT) / (double)(androids->getSize()  ));
	unsigned long long maxCount       = min(maxWeightCount, maxSizeCount);
	unsigned long long maxTransfer    = ullSafeSub(maxCount, this->mechanics.androids()->getCount());

	return maxTransfer;
};

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

unsigned long long baseClass::maxEnergeticCellsShellCanAccept(energeticCellClass * cells)
{
	if ((!(this->isShell(0))) || (!cells))
	{
		return 0;
	}

	unsigned long long maxWeightCount = (unsigned long long)((double)(this->loadingWeightLimit()  ) * (double)(SHELL_ENERGETIC_CELLS_LOADING_LIMIT) / (double)(cells->getWeight()));
	unsigned long long maxSizeCount   = (unsigned long long)((double)(this->loadingCapacityLimit()) * (double)(SHELL_ENERGETIC_CELLS_LOADING_LIMIT) / (double)(cells->getSize()  ));
	unsigned long long maxCount       = min(maxWeightCount, maxSizeCount);
	unsigned long long maxTransfer    = ullSafeSub(maxCount, this->warehouse.energeticCell()->getCount());

	return maxTransfer;
};

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

unsigned long long baseClass::maxTitaniumShellCanAccept()
{
	if (!(this->isShell(0)))
	{
		return 0;
	}

	return ullSafeSub(this->weight_, this->buildingPoints_);
};

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

unsigned long long baseClass::maxEnergyShellCanAccept()
{
	return this->freeSpaceForEnergyInTeraJoules(1, 0);
};

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

void baseClass::acceptAndroidsIntoShell(androidsClass * androids, unsigned long long working)
{
	if ((!(this->isShell(0))) || (!androids))
	{
		return;
	}

	this->mechanics.mountAndroids(androids, min(working, this->maxAndroidsShellCanAccept(androids)));
};

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

void baseClass::acceptEnergeticCellsIntoShell(energeticCellClass * cells, unsigned long long working)
{
	if ((!(this->isShell(0))) || (!cells))
	{
		return;
	}

	if (this->warehouse.nullEnergeticCell())
	{
		this->warehouse.setEnergeticCellID(actx->cacheItemsList.insertItem(cells->createEmptyCopyOfItemOfTheSameClass()));
	}
	this->warehouse.energeticCell()->addWorking(min(working, this->maxEnergeticCellsShellCanAccept(cells)));
};

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

void baseClass::acceptBundleAsShell(tradeBundleClass * bundle)
{
	if (!(this->isShell(0)))
	{
		return;
	}

	this->addTitaniumDirectlyToTheShell(bundle->getTitaniumInKg());
	this->addEnergy                    (bundle->getEnergyInTJ()  );

	for (tradeMap::iterator litp1 = bundle->bundleBegin(); bundle->bundleEnd() != litp1; litp1++)
	{
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(litp1->first);
		if (PATTERN_ID_ANDROIDS == item->getPatternID())
		{
			this->acceptAndroidsIntoShell((androidsClass *)item, litp1->second.workingCount);
		}
		if (PATTERN_ID_ENERGETIC_CELL == item->getPatternID())
		{
			this->acceptEnergeticCellsIntoShell((energeticCellClass *)item, litp1->second.workingCount);
		}
	}
};

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

dv_time::datetime baseClass::baseConstructingPhase(dv_time::datetime updateToATime)
{
	if (this->isConstructed(1))
	{
		errLogicalError("Base Constructing Phase called on constructed base (ID %u).", (unsigned long long)this->getID());
	}
	if (0 == this->energyUpdate_)
	{
		this->energyUpdate_ = updateToATime - dv_time::encodeSeconds(1);
	}
	if ((0 == this->mechanics.androids()->actualWorkingConsumption(this->realmID_)) ||
		(0 == this->weight_)                                                        ||
		(0 == this->mechanics.androids()->getWorking())                             ||
		(0 == this->mechanics.androids()->actualPointsPerSecond(this))              ||
		(0 == this->totalStructuralIntegrity_))
	{
		return MAX_SECONDS_BETWEEN_ENERGETIC_PHASES;
		// tady osetruji deleni nulou
	}
	unsigned long long possibleBuildingSeconds  = dv_time::secondsBegunBetween(this->energyUpdate_, updateToATime, 1);
	unsigned long long maxBuildingSeconds       = (unsigned long long)(this->energy_ / this->mechanics.androids()->actualWorkingConsumption(this->realmID_));
	unsigned long long realBuildingSeconds      = min(possibleBuildingSeconds, maxBuildingSeconds);
	unsigned long long maxConstructedPoints     = realBuildingSeconds * this->mechanics.androids()->getWorking() * this->mechanics.androids()->actualPointsPerSecond(this);
//	unsigned long long maxConstructedWeight     = ullUpRound((double)this->weight_ / (double)this->totalStructuralIntegrity_ * (double)maxConstructedPoints);
//	unsigned long long realConstructedWeight    = min(maxConstructedWeight, (unsigned long long)this->titanium_);
	unsigned long long realConstructedPoints    = min(maxConstructedPoints, (unsigned long long)(this->titanium_));
	this->buildingPoints_                      += realConstructedPoints;
	this->buildingPoints_                       = min(this->buildingPoints_, this->weight_);
	this->energy_                              -= (double)realBuildingSeconds * this->mechanics.androids()->actualWorkingConsumption(this->realmID_);
	this->energy_                               = max((double)0, this->energy_);
	this->titanium_                            -= (double)realConstructedPoints;
	this->titanium_                             = max((double)0, this->titanium_);
	this->energyUpdate_                         = updateToATime;
	unsigned long long secondsToEnergyLack      = (unsigned long long)(this->energy_ / this->mechanics.androids()->actualWorkingConsumption(this->realmID_));
	unsigned long long secondsToTitaniumLack    = (unsigned long long)(this->titanium_ / ((double)this->mechanics.androids()->getWorking() * (double)this->mechanics.androids()->actualPointsPerSecond(this)));
	unsigned long long secondsToFinish          = ullUpRound((double)(this->weight_ - this->buildingPoints_) / (double)(this->mechanics.androids()->getWorking() * this->mechanics.androids()->actualPointsPerSecond(this)));
	unsigned long long secondsToMaxConst        = MAX_SECONDS_BETWEEN_ENERGETIC_PHASES;
	unsigned long long secondsToUpdate          = min(MAX_SECONDS_BETWEEN_ENERGETIC_PHASES, min(secondsToEnergyLack, min(secondsToTitaniumLack, secondsToFinish)));
	dv_time::datetime nextUpdate                = updateToATime + dv_time::encodeSeconds(secondsToUpdate);
	if (0 == secondsToUpdate)
	{
		nextUpdate = MAX_SECONDS_BETWEEN_ENERGETIC_PHASES;
	}
	return nextUpdate;
};

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

unsigned short baseClass::shellDeflection(unsigned long energyPassedByShields)
{
	if (this->isConstructed(0))
	{
		errLogicalError("Shell deflection to base (ID %u).", (unsigned long long)this->getID());
		return 0;
	}

	this->energyDistributionPhaseAndWeaponsFire();

	unsigned short damagePerc  = min((unsigned short)HUNDRED_PERCENT, usUpRound((double)HUNDRED_PERCENT * (double)energyPassedByShields / (double)this->totalStructuralIntegrity_));
	this->buildingPoints_     -= min(this->buildingPoints_, (unsigned long long)energyPassedByShields);

	if (!(0 < this->buildingPoints_))
	{
		this->annihilate();
		return damagePerc;
	}

	unsigned short androidsDamagePerc = usRollA0ToNSidedDice(2 * SHELL_DAMAGE_MULTIPLICATOR * damagePerc); // dvojkou se to nasobi, protoze stredni hodnota hodu N-stennou kostkou je N pul
	unsigned short cellsDamagePerc    = usRollA0ToNSidedDice(2 * SHELL_DAMAGE_MULTIPLICATOR * damagePerc); // dvojkou se to nasobi, protoze stredni hodnota hodu N-stennou kostkou je N pul
	this->mechanics.androids()->subWorking     (ullUpRound((double)(this->mechanics.androids()->getCount())      * (double)(androidsDamagePerc) / (double)(HUNDRED_PERCENT)));
	this->warehouse.energeticCell()->subWorking(ullUpRound((double)(this->warehouse.energeticCell()->getCount()) * (double)(cellsDamagePerc)    / (double)(HUNDRED_PERCENT)));

	this->energyDistributionPhaseAndWeaponsFire();

	return damagePerc;
};

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

void baseClass::shipsAndBasesDamage(unsigned short damagePerc, unsigned short actualStructuralIntegrityPerc, bool & annihilated)
{
	unsigned short damagingCycles;
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_HANGARS_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_HANGARS_CHANCE))
		{
			hangarsDamage(usRollA0ToNSidedDice(HULL_DAMAGE_HANGARS_SIGNIFICANCE));
		}
	}
	damagingCycles = min(damagePerc, usSafeSub(HULL_DAMAGE_FACTORIES_CONDITION, actualStructuralIntegrityPerc));
	for (unsigned short loop1 = 0; loop1 < damagingCycles; ++loop1)
	{
		if (rollADice(HULL_DAMAGE_FACTORIES_CHANCE))
		{
			factoriesDamage(usRollA0ToNSidedDice(HULL_DAMAGE_FACTORIES_SIGNIFICANCE));
		}
	}
};

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

bool baseClass::isPossibleToQuarryQuarkGluonPlasma(spaceRegularObject ** quarryingPlatform)
{
	if ((this->isShell(0)                                                       ) ||
		(!(0 < this->miningDevices.magneticalCollectorsOfPlasma()->getWorking())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}

	if (quarryingPlatform)
	{
		(*quarryingPlatform) = NULL;
	}
	return 0;
};

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

bool baseClass::isPossibleToQuarryHeavyWater(spaceRegularObject ** quarryingPlatform)
{
	if ((this->isShell(0)                                                    ) ||
		(!(0 < this->miningDevices.submersibleFiltrationTank()->getWorking())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}

	if (quarryingPlatform)
	{
		(*quarryingPlatform) = this->getFortressPlanet();
	}
	return 1;
};

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

bool baseClass::isPossibleToQuarryZirconiumCrystal(spaceRegularObject ** quarryingPlatform)
{
	if ((this->isShell(0)                                                 ) ||
		(!(0 < this->miningDevices.submarineMiningMachine()->getWorking())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}

	if (quarryingPlatform)
	{
		(*quarryingPlatform) = this->getFortressPlanet();
	}
	return 1;
};

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

bool baseClass::isPossibleToQuarryIlmenite(spaceRegularObject ** quarryingPlatform)
{
	if ((this->isShell(0)                                                     ) ||
		(!(0 < this->miningDevices.undergroundDrillingMachine()->getWorking())))
	{
		if (quarryingPlatform)
		{
			(*quarryingPlatform) = NULL;
		}
		return 0;
	}

	if (quarryingPlatform)
	{
		(*quarryingPlatform) = this->getFortressPlanet();
	}
	return 1;
};

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

unsigned long long baseClass::loadingWeightLimit()
{
	return (unsigned long long)(weight_) * (unsigned long long)(BASE_LOADING_WEIGHT_LIMIT) -
		   hangarsPort.getHangarsPortWeight()                                             -
		   factories.getFactoriesWeight();
};

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

unsigned long long baseClass::loadingCapacityLimit()
{
	return loadingWeightLimit() / ullHandleZero(MINIMAL_DENSITY_OF_BASE_CARGO) - 
		   accommodations.getAccomodationsSize()                               -
		   hangarsPort.getHangarsPortSize()                                    -
		   factories.getFactoriesSize();
};

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

unsigned long long baseClass::actualTotalCargoWeight(bool doNotUpdate, bool ignoreResources, bool softUpdate)
{
	unsigned long long result = fortressCoreOnlyCargoWeight(doNotUpdate, ignoreResources, softUpdate);

	result += hangarsPort.getHangarsPortWeight();
	result += factories.getFactoriesWeight();
	// hangary a tovarny se odecitaji od celkove hmotnosti

	return result;
};

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

unsigned long long baseClass::actualSizeOfCargoInWarehouse()
{
	unsigned long long result = fortressCoreOnlySizeOfCargoInWarehouse();

	return result;
};

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

unsigned long long baseClass::freeWeight(bool doNotUpdate, bool ignoreResources, bool softUpdate)
{
	return ullSafeSub(loadingWeightLimit(), actualTotalCargoWeight(doNotUpdate, ignoreResources, softUpdate));
};

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

unsigned long long baseClass::freeCapacity()
{
	return ullSafeSub(loadingCapacityLimit(), actualSizeOfCargoInWarehouse());
};

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

bool baseClass::isHangarMounted(dtIdentifier hangarID)
{
	return this->hangarsPort.isHangarMounted(hangarID);
};

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

vector_dist_t baseClass :: MovementGetBasePosition(void)
{
    spaceObject* obj = actx->cacheSpaceObjectList.getItem<spaceObject>(spaceObjectId_);
    if (obj != NULL)
    {
        dtIdentifier parent = obj->getParentSpaceObject();
        spaceRegularObject* par = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(parent);
        if (par != NULL)
        {
            return par->getAbsolutePosition();
        }
        else
        {
            errExceptionError("Space object holder parent [%u] for base [%u] not found!", (unsigned long long) parent, (unsigned long long) getID());
            return vector_dist_t(0, 0);
        }
    }
    else
    {
        errExceptionError("Space object holder [%u] for base [%u] not found!", (unsigned long long) spaceObjectId_, (unsigned long long) getID());
        return vector_dist_t(0, 0);
    }
}

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

void baseClass :: UpdateEvents()
{
    fortressClass :: UpdateEvents();

    // updatujeme hangary
    dtIdentifierDeque :: const_iterator begin = hangarsPort.beginHangarsIdentifiers();
    dtIdentifierDeque :: const_iterator end   = hangarsPort.endHangarsIdentifiers();
    
    for (dtIdentifierDeque :: const_iterator iter = begin; iter != end; iter++)
    {
        hangarClass* cls = hangarsPort.hangarByIdentifier(*iter);
        if (cls != NULL)
        {
            cls->checkConstruction(this);
        }
    }
}

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

spaceFortressObject * baseClass :: getFortressSpaceObjectHolder(void)
{
    return actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectId_);
}

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

dtIdentifier baseClass :: getFortressSpaceObjectHolderId(void) const
{
    return spaceObjectId_;
}

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

spacePlanetObject * baseClass :: getFortressPlanet(void)
{
    spaceFortressObject * fh = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(spaceObjectId_);
    if (fh != NULL)
    {
        return actx->cacheSpaceObjectList.getItem<spacePlanetObject>(fh->getParentSpaceObject());
    }
    else
        return NULL;
}

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

dist_t baseClass :: getDistanceFromSpaceObject(dtIdentifier spaceObjectID)
{
    spacePlanetObject*  planet = getFortressPlanet();
    spaceRegularObject* other  = actx->cacheSpaceObjectList.getItem<spaceRegularObject>(spaceObjectID);

    if (planet == NULL || other == NULL)
    {
        errLogicalError("Planet or other object is NULL at fortress %u", (unsigned long long)getID());
        return std :: numeric_limits<dist_t> :: infinity();
    }
    else
    {
        return (planet->getAbsolutePosition() - other->getAbsolutePosition()).norm();
    }
}

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

bool baseClass :: getActualPosition(vector_dist_t& result)
{
    spacePlanetObject*  planet = getFortressPlanet();
    if (planet == NULL)
    {
        errLogicalError("Base %u lies on NULL planet!", (unsigned long long)getID());
        return false;
    }

    result = planet->getAbsolutePosition();

    return true;
}

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

void baseClass :: beforeDelete()
{
    spaceFortressObject * holder = getFortressSpaceObjectHolder();
    spacePlanetObject*    planet = getFortressPlanet();

    planet->subObjectRem(holder->getID());
    actx->cacheSpaceObjectList.deleteItem(holder->getID());
}

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

bool fortressClass :: distanceBetweenTwoFortresses(fortressClass* a, fortressClass* b, dist_t& result)
{
    vector_dist_t posA;
    vector_dist_t posB;

    if (a->getActualPosition(posA) && b->getActualPosition(posB))
    {
        result = (posA - posB).norm();
        return true;
    }
    else
    {
		result = 0;
        return false;
    }
}

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

bool fortressClass :: distanceBetweenTwoFortresses(dtIdentifier a, dtIdentifier b, dist_t& result)
{
    fortressClass* fA = actx->cacheFortressesList.getItem<fortressClass>(a);
    if (fA == NULL)
    {
        errLogicalError("Fortress %u doesn't exist!", (unsigned long long)a);
        return false;
    }

    fortressClass* fB = actx->cacheFortressesList.getItem<fortressClass>(b);
    if (fB == NULL)
    {
        errLogicalError("Fortress %u doesn't exist!", (unsigned long long)b);
        return false;
    }

    return distanceBetweenTwoFortresses(fA, fB, result);
}

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