wootook-reloaded/includes/application/code/community/Legacies/Empire/Model/Planet.php
2011-06-28 13:02:55 +02:00

686 lines
No EOL
22 KiB
PHP

<?php
/**
*
* @uses Legacies_Object
* @uses Legacies_Empire
* @uses Legacies_Empire_User
*/
class Legacies_Empire_Model_Planet
extends Legacies_Core_Entity
{
const TYPE_PLANET = 1;
const TYPE_DEBRIS = 2;
const TYPE_MOON = 3;
protected $_eventPrefix = 'planet.';
protected $_user = null;
protected $_moon = null;
protected $_builder = null;
protected $_shipyard = null;
protected static $_instances = array();
protected static $_productionInstances = array();
public static function factory($id)
{
if ($id === null) {
return new self();
}
$id = intval($id);
if (!isset(self::$_instances[$id])) {
$instance = new self();
$params = func_get_args();
call_user_func_array(array($instance, 'load'), $params);
self::$_instances[$id] = $instance;
}
return self::$_instances[$id];
}
public function _init()
{
$this->_tableName = 'planets';
$this->_idFieldName = 'id';
$this->_builder = new Legacies_Empire_Model_Planet_Builder($this, $this->getUser());
}
public function _afterLoad()
{
parent::_afterLoad();
$this->_builder->init();
return $this;
}
public function getLastUpdate()
{
return $this->getData('last_update');
}
public function setLastUpdate($time)
{
return $this->setData('last_update', $time);
}
public function updateStorages($time = null)
{
Math::setPrecision(50);
$resources = Legacies_Empire_Model_Game_Resources::getSingleton();
foreach ($resources->getAllDatas() as $resource => $resourceData) {
if (!isset($resourceData['storage_field']) || $resourceData['storage_field'] === null) {
continue;
}
$officerEnhancement = (.5 * $this->getUser()->getData('rpg_stockeur')) + 1;
$storageEnhancementFactor = Math::floor(Math::pow(1.6, $this[Legacies_Empire::getFieldName($resourceData['storage'])]));
$storageEnhancement = Math::mul(BASE_STORAGE_SIZE / 2, $storageEnhancementFactor);
$value = Math::mul(MAX_OVERFLOW, Math::mul($officerEnhancement, Math::add(BASE_STORAGE_SIZE, $storageEnhancement)));
$this->setData($resourceData['storage_field'], Math::floor($value));
}
Math::setPrecision();
return $this;
}
public function updateBuildingFields()
{
$types = Legacies_Empire_Model_Game_Types::getSingleton();
if ($this->isPlanet()) {
$filter = Legacies_Empire::TYPE_BUILDING_PLANET;
} else if ($this->isMoon()) {
$filter = Legacies_Empire::TYPE_BUILDING_MOON;
} else {
return $this;
}
$usedFields = 0;
foreach ($types[$filter] as $buildingId) {
$usedFields += $this->getElement($buildingId);
}
$this->setData('field_current', $usedFields);
return $this;
}
public function updateResourceProduction($time = null)
{
$types = Legacies_Empire_Model_Game_Types::getSingleton();
$resources = Legacies_Empire_Model_Game_Resources::getSingleton();
$production = Legacies_Empire_Model_Game_Production::getSingleton();
if ($time === null) {
$time = Legacies::now();
}
if (!$this->isPlanet()) {
return $this;
}
/*
* Compute resources consumers and resources producers
*/
$resourcesTotals = array();
$resourcesProductionTotals = array();
$resourcesConsumptionTotals = array();
$resourcesProducers = array();
$resourcesConsumers = array();
$productionRatios = array();
foreach ($resources->getAllDatas() as $resource => $resourceData) {
foreach ($resourceData['production'] as $productionUnit => $ratioField) {
if (!in_array($productionUnit, $types['prod'])) {
continue;
}
$level = $this->getData(Legacies_Empire::getFieldName($productionUnit));
$ratio = $this->getData($ratioField);
$element = self::getProductionElementInstance($productionUnit);
$productionRatios[$productionUnit] = $element->getProductionRatios($level, $ratio, $this, $this->getUser());
foreach ($productionRatios[$productionUnit] as $resourceId => $resourceProduction) {
$comp = Math::comp($resourceProduction, 0);
if ($comp < 0) {
if (!isset($resourcesConsumers[$resourceId])) {
$resourcesConsumers[$resourceId] = array();
}
$resourcesConsumers[$resourceId][] = $productionUnit;
if (!isset($resourcesConsumptionTotals[$resourceId])) {
$resourcesConsumptionTotals[$resourceId] = 0;
}
$resourcesConsumptionTotals[$resourceId] = Math::add($resourcesConsumptionTotals[$resourceId], $resourceProduction);
if (!isset($resourcesTotals[$resourceId])) {
$resourcesTotals[$resourceId] = 0;
}
$resourcesTotals[$resourceId] = Math::add($resourcesTotals[$resourceId], $resourceProduction);
} else if ($comp > 0) {
if (!isset($resourcesProducers[$resourceId])) {
$resourcesProducers[$resourceId] = array();
}
$resourcesProducers[$resourceId][] = $productionUnit;
if (!isset($resourcesProductionTotals[$resourceId])) {
$resourcesProductionTotals[$resourceId] = 0;
}
$resourcesProductionTotals[$resourceId] = Math::add($resourcesProductionTotals[$resourceId], $resourceProduction);
if (!isset($resourcesTotals[$resourceId])) {
$resourcesTotals[$resourceId] = 0;
}
$resourcesTotals[$resourceId] = Math::add($resourcesTotals[$resourceId], $resourceProduction);
}
}
}
}
/*
* Compute resource consumption
*/
$actualProduction = $resourcesTotals;
foreach ($resourcesTotals as $resource => $total) {
if (Math::isPositiveOrZero($total, 0)) {
continue;
}
$productionRatio = 0;
if (isset($resourcesProductionTotals[$resource]) && Math::isPositive($resourcesProductionTotals[$resource])) {
$consumptions = Math::mul(-1, $resourcesConsumptionTotals[$resource]);
Math::setPrecision(50);
$productionRatio = Math::div($resourcesProductionTotals[$resource], $consumptions);
Math::setPrecision();
}
foreach ($resourcesConsumers[$resource] as $consumer) {
foreach ($productionRatios[$consumer] as $resourceId => $ratio) {
Math::setPrecision(50);
$productionOverhead = Math::mul(Math::sub(1, $productionRatio), $ratio);
Math::setPrecision();
$actualProduction[$resourceId] = Math::sub($actualProduction[$resourceId], $productionOverhead);
}
}
}
foreach ($actualProduction as $resource => $production) {
$this->setData($resources[$resource]['production_field'], $production);
}
return $this;
}
public function updateResources($time = null)
{
$resources = Legacies_Empire_Model_Game_Resources::getSingleton();
if ($time === null) {
$time = Legacies::now();
}
$timeDiff = ($time - $this->getLastUpdate()) / 3600;
foreach ($resources->getAllDatas() as $resourceId => $resourceConfig) {
$production = Math::mul($this->getData($resourceConfig['production_field']), $timeDiff);
$resourceValue = Math::add($this->getData($resourceConfig['field']), $production);
$this->setData($resourceConfig['field'], Math::min($resourceValue, $this->getData($resourceConfig['storage_field'])));
}
$this->setLastUpdate($time);
return $this;
}
public static function getProductionElementInstance($buildingId)
{
$production = Legacies_Empire_Model_Game_Production::getSingleton();
if (!isset(self::$_productionInstances[$buildingId])) {
if (!isset($production[$buildingId])) {
return null;
}
$class = $production[$buildingId][Legacies_Empire::RESOURCE_CLASS];
$reflection = new ReflectionClass($class);
self::$_productionInstances[$buildingId] = $reflection->newInstance();
}
return self::$_productionInstances[$buildingId];
}
public function getFleetCollection($time = null)
{
$firstCollection = new Legacies_Core_Collection(array('fleet' => 'fleets'));
$firstCollection
->column('*')
->where('fleet.fleet_start_galaxy = :galaxy')
->where('fleet.fleet_start_system = :system')
->where('fleet.fleet_start_planet = :position')
->where('fleet.fleet_start_type = :planet_type')
;
$backCollection = new Legacies_Core_Collection(array('fleet' => 'fleets'));
$backCollection
->column('*')
->where('fleet.fleet_end_galaxy = :galaxy')
->where('fleet.fleet_end_system = :system')
->where('fleet.fleet_end_planet = :position')
->where('fleet.fleet_end_type = :planet_type')
;
$options = array(
'galaxy' => $this->getSystem(),
'system' => $this->getSystem(),
'position' => $this->getPosition(),
'planet_type' => $this->getType()
);
if ($time !== null) {
$options['now'] = $time;
$firstCollection->where('fleet_start_time <= :now');
$backCollection->where('fleet_end_time <= :now');
}
$collection = new Legacies_Core_Collection();
$collection
->setEntityClassName('Legacies_Empire_Model_Fleet')
->union($firstCollection)
->union($backCollection)
->load($options)
;
return $collection;
}
public function getUser()
{
if ($this->_user === null) {
$this->_user = Legacies_Empire_Model_User::factory($this->getData('id_owner'));
}
return $this->_user;
}
public function setUser(Legacies_Empire_Model_User $user)
{
$this->_user = $user;
return $this;
}
public function getShipyard()
{
if ($this->_shipyard === null) {
$this->_shipyard = new Legacies_Empire_Model_Planet_Building_Shipyard($this, $this->getUser());
}
return $this->_shipyard;
}
public function setShipyard(Legacies_Empire_Model_Planet_Building_Shipyard $shipyard)
{
$this->_shipyard = $shipyard;
return $this;
}
public function isPlanet()
{
return (bool) ($this->getData('planet_type') == self::TYPE_PLANET);
}
public function isDebris()
{
return (bool) ($this->getData('planet_type') == self::TYPE_DEBRIS);
}
public function isMoon()
{
return (bool) ($this->getData('planet_type') == self::TYPE_MOON);
}
public function getMoon()
{
static $statement = null;
if ($this->isMoon()) {
return null;
}
if ($this->_moon === null) {
if ($statement === null) {
$statement = new Legacies_Core_Collection(array('planet' => 'planets'), get_class($this));
$statement
->where('galaxy=:galaxy')
->where('system=:system')
->where('planet=:position')
->where('planet_type=' . strval(self::TYPE_MOON))
;
}
$statement->load(array(
'galaxy' => $this->getGalaxy(),
'system' => $this->getSystem(),
'position' => $this->getPosition()
));
$this->_moon = $statement->current();
}
return $this->_moon;
}
public function setGalaxy($galaxy)
{
$this->setData('galaxy', $galaxy);
return $this;
}
public function getGalaxy()
{
return (int) $this->getData('galaxy');
}
public function setSystem($system)
{
$this->setData('system', $system);
return $this;
}
public function getSystem()
{
return (int) $this->getData('system');
}
public function setPosition($position)
{
$this->setData('planet', $position);
return $this;
}
public function getPosition()
{
return (int) $this->getData('planet');
}
public function setType($type)
{
$this->setData('planet_type', $type);
return $this;
}
public function getType()
{
return (int) $this->getData('planet_type');
}
public function getElement($elementId)
{
$fields = Legacies_Empire_Model_Game_FieldsAlias::getSingleton();
return $this->getData($fields[$elementId]);
}
public function setElement($elementId, $level)
{
$fields = Legacies_Empire_Model_Game_FieldsAlias::getSingleton();
return $this->setData($fields[$elementId], $level);
}
public function hasElement($elementId, $levelRequired = 0)
{
$fields = Legacies_Empire_Model_Game_FieldsAlias::getSingleton();
return $this->hasData($fields[$elementId]) && Math::comp($this->getElement($elementId), $levelRequired) > 0;
}
public function appendBuildingQueue($buildingId, $destroy = false, $time = null)
{
$types = Legacies_Empire_Model_Game_Types::getSingleton();
$prices = Legacies_Empire_Model_Game_Prices::getSingleton();
if ($time === null) {
$time = Legacies::now();
}
if (!$types->is($buildingId, Legacies_Empire::TYPE_BUILDING)) {
return $this;
}
if ($destroy === false && !$this->checkAvailability($buildingId)) {
return $this;
}
// Dispatch 'planet.building.append-queue.before' event
Legacies::dispatchEvent($this->_eventPrefix . 'building.append-queue.before', array(
'bulding_id' => $buildingId,
'level' => $this->getElement($buildingId),
'planet' => $this,
'user' => $this->getUser(),
'destroy' => $destroy
));
if ($destroy === false) {
$level = $this->getElement($buildingId) + 1;
} else {
$level = max($this->getElement($buildingId) - 1, 0);
}
$this->_builder->appendQueue($buildingId, $level, $time);
// Dispatch 'planet.shipyard.append-queue.after' event
Legacies::dispatchEvent($this->_eventPrefix . 'building.append-queue.after', array(
'bulding_id' => $buildingId,
'level' => $this->getElement($buildingId),
'planet' => $this,
'user' => $this->getUser(),
'destroy' => $destroy
));
return $this;
}
public function updateBuildingQueue($time = null)
{
if ($time === null) {
$time = Legacies::now();
}
// Dispatch event
Legacies::dispatchEvent($this->_eventPrefix . 'update-queue.before', array(
'time' => &$time,
'planet' => $this->_currentPlanet,
'user' => $this->_currentUser
));
$this->_builder->updateQueue($time);
// Dispatch event
Legacies::dispatchEvent($this->_eventPrefix . 'update-queue.after', array(
'time' => $time,
'shipyard' => $this,
'planet' => $this->_currentPlanet,
'user' => $this->_currentUser
));
return $this;
}
public function getBuildingQueue()
{
return $this->_builder;
}
/**
* Check if a building is actually buildable on the current planet,
* depending on the technology and buildings requirements.
*
* @param int $buildingId
* @return bool
*/
public function checkAvailability($buildingId)
{
$this->_builder->checkAvailability($buildingId);
try {
// Dispatch event. Throw an exception to break the avaliability.
Legacies::dispatchEvent($this->_eventPrefix . 'check-availability', array(
'ship_id' => $buildingId,
'shipyard' => $this,
'planet' => $this->_currentPlanet,
'user' => $this->_currentUser
));
} catch (Exception $e) {
return false;
}
return true;
}
/**
* Get the resources needed to build a specific building
*
* @param int $buildingId
* @return bool
*/
public function getResourcesNeeded($buildingId, $level)
{
return $this->_builder->getResourcesNeeded($buildingId, $level);
}
/**
* Get the time needed to build a specific building
*
* @param int $buildingId
* @return bool
*/
public function getBuildingTime($buildingId, $level)
{
return $this->_builder->getBuildingTime($buildingId, $level);
}
public static function registrationListener($eventData)
{
if (isset($eventData['user'])) {
$user = $eventData['user'];
$request = $eventData['request'];
if ($user === null || !$user instanceof Legacies_Empire_Model_User || $user->getId()) {
return;
}
if ($request === null || !$request instanceof Legacies_Core_Controller_Request) {
return;
}
$collection = new Legacies_Core_Collection('planets');
$collection
->column(array(
'galaxy' => 'planet.galaxy',
'system' => 'planet.system',
'count' => 'COUNT(planet.id)'
))
->group('planet.galaxy')
->group('planet.system')
->where('planet.planet_type=1')
->order('COUNT(planet.id)', 'ASC')
->order('RAND()', 'ASC')
->limit(1)
;
$params = array();
$galaxy = $request->getParam('system');
if ($galaxy !== null) {
$collection->where('planet.galaxy=:galaxy');
$params['galaxy'] = $galaxy;
$systems = explode(',', $request->getParam('system'));
if (is_array($systems) && count($systems) == 2 && is_int($systems[0]) && is_int($systems[1])) {
$collection->where('planet.system IN(' . implode(', ', range($systems[0], $systems[1])) . ')');
}
}
$collection->load($params);
if ($collection->count() == 0) {
throw new Exception('No planet to colonize there!'); // FIXME
}
$systemInfo = $collection->current();
if ($systemInfo->getData('count') >= MAX_PLANET_IN_SYSTEM) {
throw new Exception('No planet to colonize there!'); // FIXME
}
$system = $systemInfo->getData('system');
$galaxy = $systemInfo->getData('galaxy');
$collection = new Legacies_Core_Collection('planets');
$collection
->column(array('position' => 'planet.position'))
->where('planet.planet_type=1')
->where('planet.planet_type=:system')
->load()
;
$positions = range(1, MAX_PLANET_IN_SYSTEM);
foreach ($collection as $planet) {
$key = array_search($planet->getData('position'), $positions);
if ($key !== false) {
unset($positions[$key]);
}
}
$key = array_rand($positions, 1);
$finalPosition = $positions[$key];
$planet = new self();
$planet
->setData('id_owner', $user->getId())
->setData('name', $request->getParam('planet'))
->setData('galaxy', $galaxy)
->setData('system', $system)
->setData('position', $finalPosition)
->setData('planet_type', 1)
;
Legacies::dispatchEvent('planet.init', array(
'planet' => $planet,
'user' => $user
));
$planet
->setData('field_max', 163)
->setData('field_current', 0)
->save()
;
$user
->setData('id_planet', $planet->getId())
->setData('current_planet', $planet->getId())
;
}
}
public static function planetUpdateListener($eventData)
{
if (isset($eventData['planet'])) {
$planet = $eventData['planet'];
if (isset($eventData['time'])) {
$time = $eventData['time'];
} else {
$time = time();
}
if ($planet === null || !$planet instanceof Legacies_Empire_Model_Planet) {
return;
}
$planet->updateBuildingQueue($time);
$planet->updateResources($time);
$planet->getShipyard()->updateQueue($time);
$planet->setLastUpdate($time);
}
}
}