//----------------------------------------------------------------------------
void CCreatureManager::fixAltar()
{
	for( TMapCreatures::iterator it = _Creatures.begin(); it != _Creatures.end(); ++it )
	{
		CCreature * c = (*it).second;
		if( c )
		{
			if( c->getAltarForNeutral() )
			{
				c->clearAltarFameRestriction();
				c->clearAltarFameRestrictionValue();
			}
		}
	}
}
Exemplo n.º 2
0
	uint processEvent( const TDataSetRow & userRow, const CMissionEvent & event,uint subStepIndex,const TDataSetRow & giverRow )
	{
		if ( event.Type == CMissionEvent::Kill )
		{
			CMissionEventKill & eventSpe = (CMissionEventKill&)event;
			CCreature * c = CreatureManager.getCreature( event.TargetEntity );
			if ( !c )
			{
				LOGMISSIONSTEPERROR("kill_fauna : invalid creature " + toString(event.TargetEntity.getIndex()));
			}
			else if ( _SubSteps[subStepIndex].Sheet == c->getType() )
			{
				if ( _Place != 0xFFFF )
				{
					float gooDistance;
					const CPlace * stable = NULL;
					std::vector<const CPlace *> places;
					const CRegion * region = NULL;
					const CContinent * continent = NULL;
					if ( !CZoneManager::getInstance().getPlace( c->getState().X, c->getState().Y, gooDistance, &stable, places, &region , &continent ) )
						return 0;

					if ( region && region->getId() == _Place )
					{
						LOGMISSIONSTEPSUCCESS("kill_fauna");
						return 1;
					}
					
					for ( uint i = 0; i < places.size(); i++ )
					{
						if ( places[i] && places[i]->getId() == _Place )
						{
							LOGMISSIONSTEPSUCCESS("kill_fauna");
							return 1;
						}
					}
					return 0;
				}
				else
				{
					LOGMISSIONSTEPSUCCESS("kill_fauna");
					return 1;
				}
			}
		}
		return 0;
	}
Exemplo n.º 3
0
/**
 * Calculates what creatures and how many to be raised from a battle.
 * @param battleResult The results of the battle.
 * @return Returns a pair with the first value indicating the ID of the creature
 * type and second value the amount. Both values are returned as -1 if necromancy
 * could not be applied.
 */
CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &battleResult) const
{
	const ui8 necromancyLevel = getSecSkillLevel(SecondarySkill::NECROMANCY);

	// Hero knows necromancy or has Necromancer Cloak
	if (necromancyLevel > 0 || hasBonusOfType(Bonus::IMPROVED_NECROMANCY))
	{
		double necromancySkill = valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::NECROMANCY)/100.0;
		vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
		const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
		ui32 raisedUnits = 0;

		// Figure out what to raise and how many.
		const CreatureID creatureTypes[] = {CreatureID::SKELETON, CreatureID::WALKING_DEAD, CreatureID::WIGHTS, CreatureID::LICHES};
		const bool improvedNecromancy = hasBonusOfType(Bonus::IMPROVED_NECROMANCY);
		const CCreature *raisedUnitType = VLC->creh->creatures[creatureTypes[improvedNecromancy ? necromancyLevel : 0]];
		const ui32 raisedUnitHP = raisedUnitType->valOfBonuses(Bonus::STACK_HEALTH);

		//calculate creatures raised from each defeated stack
		for (auto & casualtie : casualties)
		{
			// Get lost enemy hit points convertible to units.
			CCreature * c = VLC->creh->creatures[casualtie.first];

			const ui32 raisedHP = c->valOfBonuses(Bonus::STACK_HEALTH) * casualtie.second * necromancySkill;
			raisedUnits += std::min<ui32>(raisedHP / raisedUnitHP, casualtie.second * necromancySkill); //limit to % of HP and % of original stack count
		}

		// Make room for new units.
		SlotID slot = getSlotFor(raisedUnitType->idNumber);
		if (slot == SlotID())
		{
			// If there's no room for unit, try it's upgraded version 2/3rds the size.
			raisedUnitType = VLC->creh->creatures[*raisedUnitType->upgrades.begin()];
			raisedUnits = (raisedUnits*2)/3;

			slot = getSlotFor(raisedUnitType->idNumber);
		}
		if (raisedUnits <= 0)
			raisedUnits = 1;

		return CStackBasicDescriptor(raisedUnitType->idNumber, raisedUnits);
	}

	return CStackBasicDescriptor();
}
//--------------------------------------------------------------
//				CChangeCreatureHPImp ::callback()  
//--------------------------------------------------------------
void CChangeCreatureHPImp::callback(const string &, NLNET::TServiceId sid)
{
	H_AUTO(CChangeCreatureHPImp);

	uint16 size = (uint16)Entities.size();
	if (Entities.size() != DeltaHp.size() )
	{
		nlwarning("Entities.size() != DeltaHp.size()");

		size = (uint16)min(Entities.size(),DeltaHp.size());
	}
	
	// for each creature, change HP
	for ( uint i = 0; i < size; ++i )
	{
		CCreature * c = CreatureManager.getCreature( Entities[i] );
		if ( c )
		{
			if( c->currentHp()+DeltaHp[i] > c->maxHp() )
			{
				// clamp hp
				c->changeCurrentHp( c->maxHp() - c->currentHp() );
			}
			else
			{
				c->changeCurrentHp( DeltaHp[i] );
			}
		}
	}
}
Exemplo n.º 5
0
void CCreatureHandler::loadBonuses(CCreature & ncre, std::string bonuses)
{
	static const std::map<std::string,Bonus::BonusType> abilityMap =
	  boost::assign::map_list_of
	    ("FLYING_ARMY", Bonus::FLYING)
	    ("SHOOTING_ARMY", Bonus::SHOOTER)
	    ("SIEGE_WEAPON", Bonus::SIEGE_WEAPON)
	    ("const_free_attack", Bonus::BLOCKS_RETALIATION)
	    ("IS_UNDEAD", Bonus::UNDEAD)
	    ("const_no_melee_penalty",Bonus::NO_MELEE_PENALTY)
	    ("const_jousting",Bonus::JOUSTING)
	    ("KING_1",Bonus::KING1)
	    ("KING_2",Bonus::KING2)
		("KING_3",Bonus::KING3)
		("const_no_wall_penalty",Bonus::NO_WALL_PENALTY)
		("CATAPULT",Bonus::CATAPULT)
		("MULTI_HEADED",Bonus::ATTACKS_ALL_ADJACENT)
		("IMMUNE_TO_MIND_SPELLS",Bonus::MIND_IMMUNITY)
		("HAS_EXTENDED_ATTACK",Bonus::TWO_HEX_ATTACK_BREATH);

	auto hasAbility = [&](const std::string name) -> bool
	{
		return boost::algorithm::find_first(bonuses, name);
	};
	BOOST_FOREACH(auto a, abilityMap)
	{
		if(hasAbility(a.first))
			ncre.addBonus(0, a.second);
	}
	if(hasAbility("DOUBLE_WIDE"))
		ncre.doubleWide = true;
	if(hasAbility("const_raises_morale"))
	{
		ncre.addBonus(+1, Bonus::MORALE);;
		ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO));
	}
	if(hasAbility("const_lowers_morale"))
	{
		ncre.addBonus(-1, Bonus::MORALE);;
		ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
	}
}
//----------------------------------------------------------------------------
bool CR2GiveItem::_ValidateGiveItemRequest( const TItemRequest &req )
{
	CCharacter *c = PlayerManager.getChar( req.CharacterRowId );
	if( c == 0 )
		return false;

	CCreature *bot = CreatureManager.getCreature( req.CreatureRowId );
	if( bot == 0)
		return false;

	if( bot->isDead() || c->isDead() )
		return false;

	for( uint i = 0; i < req.ItemsRequest.size(); ++i )
	{
		if( req.ItemsRequest[i].Quantity > CR2MissionItem::getInstance().getNumberMissionItem(c->getId(), req.ItemsRequest[i].SheetId ) )
			return false;
	}
	return true;
}
//--------------------------------------------------------------
//				CFaunaBotDescription ::callback()  
//--------------------------------------------------------------
void CFaunaBotDescriptionImp::callback(const string &, NLNET::TServiceId sid)
{
	H_AUTO(CFaunaBotDescriptionImpCallback);

	if ( Bots.size() != GrpAlias.size() )
	{
		nlwarning("<CFaunaBotDescription callback> the two vectors do not have the same size!");
	}
	// for each bot, set its new group alias
	for ( uint i = 0; i < Bots.size(); i++ )
	{
		CCreature * c = CreatureManager.getCreature( Bots[i] );
		if ( c )
		{
			c->setAIGroupAlias( GrpAlias[i] );
		}
		else
		{
			CreatureManager.addUnaffectedFaunaGroup(  Bots[i], GrpAlias[i] ) ;
		}
	}
}
//----------------------------------------------------------------------------
 void CR2GiveItem::giveItemGranted( TDataSetRow creatureRowId, uint32 actionId )
{
	TPendingRequest::iterator it = _PendingRequest.find( creatureRowId );
	if( it != _PendingRequest.end() )
	{
		TCreatureItemRequest &vec = (*it).second;
		for( uint32 i = 0; i < vec.size(); ++ i)
		{
			if( vec[i].ActionId == actionId )
			{
				CCharacter *c = PlayerManager.getChar( vec[i].CharacterRowId );
				nlassert(c);
				CCreature *e = CreatureManager.getCreature(creatureRowId);
				CMirrorPropValueRO<TYPE_SHEET> sheetInMirror( TheDataset, creatureRowId, DSPropertySHEET );
				NLMISC::CSheetId sheetId(sheetInMirror());
				const CStaticCreatures *clientCreatureForm = CSheets::getCreaturesForm( sheetId );
				if(e == NULL) return; 
				sint32 dx = c->getX() - e->getX();
				sint32 dy = c->getY() - e->getY();
				sint32 sqrDist = dx*dx + dy*dy;
				sint32 squareCreatureColRadius = 0;
				if(clientCreatureForm != 0)
				{
					squareCreatureColRadius = (sint32)(1000.0f * max(clientCreatureForm->getColRadius(), max(clientCreatureForm->getColWidth(),clientCreatureForm->getColLength())));
					squareCreatureColRadius= squareCreatureColRadius * squareCreatureColRadius;
				}

				if (sqrDist > (MaxTalkingDistSquare * 1000 * 1000 + squareCreatureColRadius))
				{
					CCharacter::sendDynamicSystemMessage( vec[i].CharacterRowId, "BS_TARGET_TOO_FAR");
					return;
				}

				CUserEventMsg eventMsg;
				eventMsg.InstanceNumber = vec[i].InstanceId;
				eventMsg.GrpAlias = vec[i].GroupAlias;
				// add the character and npc as parameter of the event
				eventMsg.Params.push_back(c->getId().toString());
				eventMsg.Params.push_back(e->getId().toString());

				if( vec[i].IsGiveItem )
				{
					if( _ValidateGiveItemRequest( vec[i] ) )
					{
						CR2MissionItem::getInstance().destroyMissionItem( c->getId(), vec[i].ItemsRequest );

						eventMsg.EventId = 3;
						CWorldInstances::instance().msgToAIInstance(eventMsg.InstanceNumber, eventMsg);
					}
				}
				else
				{
					CR2MissionItem::getInstance().giveMissionItem( c->getId(), c->currentSessionId(), vec[i].ItemsRequest );
					
					eventMsg.EventId = 1;
					CWorldInstances::instance().msgToAIInstance(eventMsg.InstanceNumber, eventMsg);
				}

				vec[i] = vec.back();
				vec.pop_back();
				
				_SetClientDBAll( c, vec );
				
				if( vec.size() == 0 )
					_PendingRequest.erase( it );
				return;
			}
		}
	}
}
//-----------------------------------------------
// CHarvestPhrase harvestCorpseResult
//-----------------------------------------------
void CHarvestPhrase::harvestCorpseResult()
{
	H_AUTO(CHarvestPhrase_harvestCorpseResult);
	
	// get harvester character
	CCharacter *character = PlayerManager.getChar( _ActorRowId );
	if (character == NULL)
	{
		//nlwarning("<cbHarvestResult> Invalid player Id %s", playerId.toString().c_str() );
		return;
	}

	// get harvested corpse
	const CEntityId &harvestedEntity = character->harvestedEntity();

	CCreature *creature = CreatureManager.getCreature( harvestedEntity );
	if (creature == NULL)
	{
		nlwarning("<cbHarvestResult> Invalid creature Id %s", harvestedEntity.toString().c_str() );
		// reset harvest info
		character->resetHarvestInfos();
		character->endHarvest();
		return;
	}

	const vector< CCreatureRawMaterial> &mps = creature->getMps();
	if ( character->harvestedMpIndex() >= mps.size() || character->harvestedMpQuantity() > mps[character->harvestedMpIndex()].Quantity )
	{
		// reset harvest info
		character->resetHarvestInfos();
		return;
	}

	uint16 quality = _MaxQuality;

	// create the mp items if any
	if (quality > 0)
	{
		if ( !character->createItemInInventory(INVENTORIES::bag, quality, character->harvestedMpQuantity(), _RawMaterialId, character->getId()) )
		{
	//		CMissionEventItem event(CMissionEvent::Harvest,playerId,harvestedEntity,_RawMaterialId,quality,character->harvestedMpQuantity());
	//		character->processMissionEvent(event);
			// error creating the object, hand probably not empty
		//	character->resetHarvestInfos();
		//	return;
		}
		else
		{
			const CStaticItem *item = CSheets::getForm(_RawMaterialId);
			if (item)
			{
				///\todo nico: check if this event exists
//				CMissionEventHarvest event(_RawMaterialId ,character->harvestedMpQuantity(),quality);
//				character->processMissionEvent( event );

				SM_STATIC_PARAMS_3(params, STRING_MANAGER::integer, STRING_MANAGER::item, STRING_MANAGER::integer);
				params[0].Int = (sint32)character->harvestedMpQuantity();
				params[1].SheetId = _RawMaterialId;
				params[2].Int = (sint32)quality;

				STRING_MANAGER::sendStringToClient( character->getEntityRowId(), "HARVEST_SUCCESS", params );
			}
		}
	}
	// the mp have been destroyed -> do nothing
	else
	{
	}

	// remove the quantity of mp harvested from the ressource
	creature->removeMp( character->harvestedMpIndex(), character->harvestedMpQuantity() );
		
	// reset harvest info
	character->resetHarvestInfos();
} // harvestCorpseResult //
// This method was tuenre into a static function to be used outside of the
// class, coz building a magic phrase ane applying a magic action should be
// distinguished but wasn't. (vuarand)
bool CMagicActionBasicDamage::applyOnEntity(
	CMagicPhrase*	phrase,
	CEntityBase*	actor,
	CEntityBase*	target,
	sint32			vamp,
	float			vampRatio,
	CTargetInfos&	targetInfos,
	
	DMGTYPE::EDamageType const	_DmgType,
	sint32 const				_DmgHp,
	sint32 const				_DmgSap,
	sint32 const				_DmgSta,
	sint32 const				_VampirismValue)
{
	// If target is immune to magic tell player and return
	if (targetInfos.Immune)
	{
		SM_STATIC_PARAMS_1(params, STRING_MANAGER::entity);
		params[0].setEIdAIAlias(target->getId(), CAIAliasTranslator::getInstance()->getAIAlias(target->getId()));
		PHRASE_UTILITIES::sendDynamicSystemMessage(actor->getEntityRowId(), "MAGIC_TARGET_IMMUNE", params);
		
		return true;
	}
	
	// If target automatically resist to magic, tell player and return
	if (targetInfos.ResistFactor <= 0.0f)
	{
		PHRASE_UTILITIES::sendSpellResistMessages(actor->getEntityRowId(), target->getEntityRowId());
		return true;
	}
	
	bool sendAggro = true;
	CCreature * npc = dynamic_cast<CCreature*>(target);
	CCharacter * c = dynamic_cast<CCharacter*>(actor);
	if(npc && c)
	{
		if(!PHRASE_UTILITIES::testRange(*actor, *target, (uint32)npc->getMaxHitRangeForPC()*1000))
		{
			const_cast<sint32&>(_DmgHp) = 0;
			const_cast<sint32&>(_DmgSap) = 0;
			const_cast<sint32&>(_DmgSta) = 0;
			const_cast<sint32&>(_VampirismValue) = 0;
			targetInfos.DmgHp = 0;
			sendAggro = false;
			c->sendDynamicSystemMessage(c->getId(), "UNEFFICENT_RANGE");
		}
	}

	sint32 realDmgHp = targetInfos.DmgHp;
	realDmgHp = sint32( target->applyDamageOnArmor( _DmgType, realDmgHp ) );
	if (realDmgHp > target->currentHp())
		realDmgHp = target->currentHp();
	
	targetInfos.ReportAction.Hp += realDmgHp;
	
	// apply vampirism
	vamp += _VampirismValue;
	if (vamp && actor->getId().getType() == RYZOMID::player)
	{
		sint32 vampirise = (sint32) (realDmgHp * vampRatio);
		if (vampirise > vamp)
			vampirise = vamp;
		
		actor->changeCurrentHp(vampirise);
		SM_STATIC_PARAMS_2(params, STRING_MANAGER::entity, STRING_MANAGER::integer);
		params[0].setEIdAIAlias(target->getId(), CAIAliasTranslator::getInstance()->getAIAlias(target->getId()));
		params[1].Int = vampirise;
		CCharacter::sendDynamicSystemMessage(actor->getId(),"EGS_ACTOR_VAMPIRISE_EI", params);
	}
	
	// apply Sap damage
	sint32 realDmgSap = 0;
	{
		SCharacteristicsAndScores& score = target->getScores()._PhysicalScores[SCORES::sap];
		sint32 maxRealDmgSap = (sint32)( _DmgSap * targetInfos.DmgFactor );
		realDmgSap = target->applyDamageOnArmor(_DmgType, maxRealDmgSap);
		if (realDmgSap != 0)
		{
			PHRASE_UTILITIES::sendScoreModifierSpellMessage(actor->getId(), target->getId(), -realDmgSap, -maxRealDmgSap, SCORES::sap, ACTNATURE::OFFENSIVE_MAGIC);
			
			if (realDmgSap > score.Current)
				realDmgSap = score.Current;
			score.Current = score.Current - realDmgSap;
			
			targetInfos.ReportAction.Sap += realDmgSap;
		}
	}
	
	// apply Stamina damage
	sint32 realDmgSta = 0;
	{
		SCharacteristicsAndScores &score = target->getScores()._PhysicalScores[SCORES::stamina];
		sint32 maxRealDmgSta =  sint32( _DmgSta * targetInfos.DmgFactor );
		realDmgSta = target->applyDamageOnArmor( _DmgType, maxRealDmgSta );
		if (realDmgSta != 0)
		{
			PHRASE_UTILITIES::sendScoreModifierSpellMessage(actor->getId(), target->getId(), -realDmgSta, -maxRealDmgSta, SCORES::stamina, ACTNATURE::OFFENSIVE_MAGIC);
			
			if (realDmgSta > score.Current)
				realDmgSta = score.Current;
			score.Current = score.Current - realDmgSta;
			
			targetInfos.ReportAction.Sta += realDmgSta;
		}
	}
	
	targetInfos.ReportAction.ActionNature = ACTNATURE::OFFENSIVE_MAGIC;
	
	// compute aggro
	sint32 max = target->maxHp();
	
	float aggroHp = 0.0f;
	float aggroSap = 0.0f;
	float aggroSta = 0.0f;
	
	CAiEventReport report;
	if (phrase)
		report.Originator = phrase->getActor();
	else
		report.Originator = actor->getEntityRowId();
	report.Target = target->getEntityRowId();
	report.Type = ACTNATURE::OFFENSIVE_MAGIC;
	if (max && _DmgHp != 0)
	{
		aggroHp = min(1.0f, float(realDmgHp)/float(max) );
		report.addDelta(AI_EVENT_REPORT::HitPoints, (-1)*realDmgHp);
	}
	
	max = target->getPhysScores()._PhysicalScores[SCORES::sap].Max;
	if (max && _DmgSap != 0)
	{
		aggroSap = min(1.0f, float(realDmgSap)/float(max) );
		report.addDelta(AI_EVENT_REPORT::Sap, (-1)*realDmgSap);
	}
	
	max = target->getPhysScores()._PhysicalScores[SCORES::stamina].Max;
	if (max && _DmgSta != 0)
	{
		aggroSta = min(1.0f,float(realDmgSta)/float(max));
		report.addDelta(AI_EVENT_REPORT::Stamina, (-1)*realDmgSta);
	}
	
	// send report
	report.AggroAdd = - min(1.0f, 1.0f - (1.0f-aggroHp)*(1.0f-aggroSap)*(1.0f-aggroSta) );
	
	if(sendAggro)
		CPhraseManager::getInstance().addAiEventReport(report);
	
	// apply Hp damage
	if (realDmgHp > 0)
	{
		if ( target->changeCurrentHp( -realDmgHp, actor->getEntityRowId()) )
		{
			PHRASE_UTILITIES::sendScoreModifierSpellMessage( actor->getId(), target->getId(), -realDmgHp, -targetInfos.DmgHp ,SCORES::hit_points , ACTNATURE::OFFENSIVE_MAGIC);
			PHRASE_UTILITIES::sendDeathMessages( actor->getEntityRowId(), target->getEntityRowId() );
		}
		else
		{
			PHRASE_UTILITIES::sendScoreModifierSpellMessage( actor->getId(), target->getId(), -realDmgHp, -targetInfos.DmgHp ,SCORES::hit_points , ACTNATURE::OFFENSIVE_MAGIC);
		}
	}
	
	return !sendAggro;
}
bool CMagicActionBasicDamage::launchOnEntity(
	CMagicPhrase*		phrase,
	CEntityBase*		actor,
	CEntityBase*		target,
	bool				mainTarget,
	uint32				casterSkillvalue,
	uint32				casterSkillBaseValue,
	MBEHAV::CBehaviour&	behav,
	bool				isMad,
	float				rangeFactor,
	CTargetInfos&		targetInfos)
{
	// for main target only, check reflect damage effects
	if (mainTarget)
	{
		const CSEffectPtr effect = target->lookForActiveEffect(EFFECT_FAMILIES::ReflectDamage);
		if ( effect )
		{
			target = actor;
			isMad = true;
		}
	}

	// change caster skill according to target race (for special items that gives a skill bonus against Kitins for exemple)
	casterSkillvalue += actor->getSkillModifierForRace(target->getRace());

	// init target infos
	targetInfos.RowId			= target->getEntityRowId();
	targetInfos.MainTarget		= mainTarget;
	targetInfos.DmgHp			= 0;
	targetInfos.ResistFactor	= 1.0f;
	targetInfos.DmgFactor		= 1.0f;
	targetInfos.Immune			= false;

	targetInfos.ReportAction.TargetRowId = target->getEntityRowId();

	if( target->getId().getType() != RYZOMID::player )
	{
		const CStaticCreatures * creatureSheet = target->getForm();
		if( creatureSheet != 0 )
		{
			targetInfos.ReportAction.DeltaLvl = casterSkillBaseValue - creatureSheet->getXPLevel();
		}
	}

	
	// test resistance
	float resistFactor = 1.0f;
	//if entity invincible, it aways resists the effect
	const CSEffectPtr effect = target->lookForActiveEffect(EFFECT_FAMILIES::Invincibility);
	if ( effect )
	{
		targetInfos.Immune = true;
		resistFactor = 0.0f;
	}
	else
	{
		if (!EntitiesNoResist)
		{
			uint32 resistValue = target->getMagicResistance(_DmgType);

			if (resistValue == CCreatureResists::ImmuneScore )
			{
				targetInfos.Immune = true;
				resistFactor = 0.0f;
			}
			else
			{
				if ( actor->getId().getType() == RYZOMID::player )
				{
					// boost magic skill for low level chars
					uint32 sb = MagicSkillStartValue.get();
					casterSkillvalue = max( sb, casterSkillvalue );

					// add magic boost from consumable
					CCharacter * pC = dynamic_cast<CCharacter *>(actor);
					if(pC)
						casterSkillvalue += pC->magicSuccessModifier();
				}

				// get the chances
				const uint8 roll = (uint8)RandomGenerator.rand( 99 );
				resistFactor = CStaticSuccessTable::getSuccessFactor(SUCCESS_TABLE_TYPE::MagicResistDirect, casterSkillvalue - resistValue, roll);

				// increase resists modifier for next resists test
				if (resistFactor > 0.0f)
					target->incResistModifier(_DmgType, resistFactor);

				if ( resistFactor <= 0.0f )
				{
					// Xp gain log
					if (PlayerManager.logXPGain(actor->getEntityRowId()))
					{
						const uint8 chances = CStaticSuccessTable::getSuccessChance( SUCCESS_TABLE_TYPE::MagicResistDirect, casterSkillvalue - resistValue ); 
						nlinfo("[XPLOG] Magic attack Actor %s on %s, delta = %d, target has Resisted (chances %u, tirage %u)", actor->getId().toString().c_str(), target->getId().toString().c_str(),
							targetInfos.ReportAction.DeltaLvl, chances, roll);
					}
				}
			}
		}
		else
		{
			resistFactor = 1.0f;
		}
	}
	if ( resistFactor > 0.0f )
	{
		if ( resistFactor > 1.0f )
			resistFactor = 1.0f;
		
		float dmgFactor = resistFactor * rangeFactor * (1.0f + phrase->getUsedItemStats().getPowerFactor(_Skill, phrase->getBrickMaxSabrinaCost()));
		
		// if PVP, apply PVP magic damage factor
		if( actor != target && actor->getId().getType() == RYZOMID::player && target->getId().getType() == RYZOMID::player)
		{
			dmgFactor *= PVPMagicDamageFactor.get();
		}

		// add spire effect ( magic offense )
		if ( actor->getId().getType() == RYZOMID::player )
		{
			CCharacter* charac = (CCharacter*)actor;
			const CSEffect* pEffect = charac->lookForActiveEffect( EFFECT_FAMILIES::TotemCombatMagOff );
			if ( pEffect != NULL )
			{
				dmgFactor *= ( 1.0f + pEffect->getParamValue() / 100.0f );
			}
		}
		
		sint32 maxDmgHp =  sint32 ( _DmgHp * dmgFactor );
		sint32 realDmgHp = target->applyDamageOnArmor( _DmgType, maxDmgHp );
		
		// update behaviour for lost Hp
		CCreature * npc = dynamic_cast<CCreature*>(target);
		CCharacter * c = dynamic_cast<CCharacter*>(actor);
		if(npc && c)
		{
			if(PHRASE_UTILITIES::testRange(*actor, *target, (uint32)npc->getMaxHitRangeForPC()*1000))
			{
				behav.DeltaHP -= (sint16)realDmgHp;
			}
			else
			{
				behav.DeltaHP = 0;
			}
		}
		
		// update target infos
		targetInfos.DmgHp			= maxDmgHp;
		targetInfos.ResistFactor	= resistFactor;
		targetInfos.DmgFactor		= dmgFactor;
		
		return false;
	}
	else
	{
		// don't tell the player now, but wait to send message when the missile hit the player (at apply() time)
		targetInfos.ResistFactor	= 0.f;
		
		CAiEventReport report;
		report.Originator = phrase->getActor();
		report.Target = target->getEntityRowId();
		report.Type = ACTNATURE::OFFENSIVE_MAGIC;
		//////////////////////////////////////////////////////////////////////////
		// TEMPORARY : set a small value for resist aggro
		//////////////////////////////////////////////////////////////////////////					
		report.AggroAdd = -0.02f;
		CCreature * npc = dynamic_cast<CCreature*>(target);
		CCharacter * c = dynamic_cast<CCharacter*>(actor);
		if(npc && c && PHRASE_UTILITIES::testRange(*actor, *target, (uint32)npc->getMaxHitRangeForPC()*1000) )
			CPhraseManager::getInstance().addAiEventReport(report);
		return true;
	}
}
Exemplo n.º 12
0
void CCreatureHandler::loadCreatures()
{
	tlog5 << "\t\tReading config/cr_abils.json and ZCRTRAIT.TXT" << std::endl;

	////////////reading ZCRTRAIT.TXT ///////////////////
	CLegacyConfigParser parser("DATA/ZCRTRAIT.TXT");

	parser.endLine(); // header
	parser.endLine();

	do
	{
		//loop till non-empty line
		while (parser.isNextEntryEmpty())
			parser.endLine();

		CCreature &ncre = *new CCreature;
		ncre.idNumber = CreatureID(creatures.size());
		ncre.cost.resize(GameConstants::RESOURCE_QUANTITY);
		ncre.level=0;
		ncre.iconIndex = ncre.idNumber + 2; // +2 for empty\selection images

		ncre.nameSing = parser.readString();
		ncre.namePl   = parser.readString();

		for(int v=0; v<7; ++v)
		{
			ncre.cost[v] = parser.readNumber();
		}
		ncre.fightValue = parser.readNumber();
		ncre.AIValue = parser.readNumber();
		ncre.growth = parser.readNumber();
		ncre.hordeGrowth = parser.readNumber();

		ncre.addBonus(parser.readNumber(), Bonus::STACK_HEALTH);
		ncre.addBonus(parser.readNumber(), Bonus::STACKS_SPEED);
		ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
		ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
		ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 1);
		ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 2);
		ncre.addBonus(parser.readNumber(), Bonus::SHOTS);

		//spells - not used?
		parser.readNumber();
		ncre.ammMin = parser.readNumber();
		ncre.ammMax = parser.readNumber();

		ncre.abilityText = parser.readString();
		ncre.abilityRefs = parser.readString();

		{ //adding abilities from ZCRTRAIT.TXT
			if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE"))
				ncre.doubleWide = true;
			if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY"))
				ncre.addBonus(0, Bonus::FLYING);
			if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY"))
				ncre.addBonus(0, Bonus::SHOOTER);
			if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
				ncre.addBonus(0, Bonus::SIEGE_WEAPON);
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
				ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
			if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
				ncre.addBonus(0, Bonus::UNDEAD);
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_melee_penalty"))
				ncre.addBonus(0, Bonus::NO_MELEE_PENALTY);
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_jousting"))
				ncre.addBonus(0, Bonus::JOUSTING);
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
			{
				ncre.addBonus(+1, Bonus::MORALE);;
				ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO));
			}
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
			{
				ncre.addBonus(-1, Bonus::MORALE);;
				ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
			}
			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1"))
				ncre.addBonus(0, Bonus::KING1);
			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_2"))
				ncre.addBonus(0, Bonus::KING2);
			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_3"))
				ncre.addBonus(0, Bonus::KING3);
			if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_wall_penalty"))
				ncre.addBonus(0, Bonus::NO_WALL_PENALTY);
			if(boost::algorithm::find_first(ncre.abilityRefs, "CATAPULT"))
				ncre.addBonus(0, Bonus::CATAPULT);
			if(boost::algorithm::find_first(ncre.abilityRefs, "MULTI_HEADED"))
				ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT);

			if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS"))
				ncre.addBonus(0, Bonus::MIND_IMMUNITY);
			if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS"))
				ncre.addBonus(0, Bonus::FIRE_IMMUNITY);
			if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK"))
				ncre.addBonus(0, Bonus::TWO_HEX_ATTACK_BREATH);;
		}
		creatures.push_back(&ncre);
	}
	while (parser.endLine());

	// loading creatures properties
	tlog5 << "\t\tReading creatures json configs" << std::endl;

	const JsonNode gameConf(ResourceID("config/gameConfig.json"));
	const JsonNode config(JsonUtils::assembleFromFiles(gameConf["creatures"].convertTo<std::vector<std::string> >()));

	BOOST_FOREACH(auto & node, config.Struct())
	{
		int creatureID = node.second["id"].Float();
		CCreature *c = creatures[creatureID];

		BOOST_FOREACH(const JsonNode &ability, node.second["ability_remove"].Vector())
		{
			RemoveAbility(c, ability);
		}
		BOOST_FOREACH(const JsonNode &ability, node.second["abilities"].Vector())
		{
			if (ability.getType() == JsonNode::DATA_VECTOR)
				AddAbility(c, ability.Vector());
			else
				c->addNewBonus(JsonUtils::parseBonus(ability));
		}

		loadCreatureJson(c, node.second);

		// Main reference name, e.g. royalGriffin
		c->nameRef = node.first;
		VLC->modh->identifiers.registerObject("creature." + node.first, c->idNumber);

		// Alternative names, if any
		BOOST_FOREACH(const JsonNode &name, node.second["extraNames"].Vector())
		{
			VLC->modh->identifiers.registerObject("creature." + name.String(), c->idNumber);
		}
	}

	loadAnimationInfo();

	//reading creature ability names
	const JsonNode config2(ResourceID("config/bonusnames.json"));

	BOOST_FOREACH(const JsonNode &bonus, config2["bonuses"].Vector())
	{
		std::map<std::string,int>::const_iterator it_map;
		std::string bonusID = bonus["id"].String();

		it_map = bonusNameMap.find(bonusID);
		if (it_map != bonusNameMap.end())
			stackBonuses[it_map->second] = std::pair<std::string, std::string>(bonus["name"].String(), bonus["description"].String());
		else
			tlog2 << "Bonus " << bonusID << " not recognized, ignoring\n";
	}

	//handle magic resistance secondary skill premy, potentialy may be buggy
	//std::map<TBonusType, std::pair<std::string, std::string> >::iterator it = stackBonuses.find(Bonus::MAGIC_RESISTANCE);
	//stackBonuses[Bonus::SECONDARY_SKILL_PREMY] = std::pair<std::string, std::string>(it->second.first, it->second.second);

	if (VLC->modh->modules.STACK_EXP) 	//reading default stack experience bonuses
	{
		CLegacyConfigParser parser("DATA/CREXPBON.TXT");

		Bonus b; //prototype with some default properties
		b.source = Bonus::STACK_EXPERIENCE;
		b.duration = Bonus::PERMANENT;
		b.valType = Bonus::ADDITIVE_VALUE;
		b.effectRange = Bonus::NO_LIMIT;
		b.additionalInfo = 0;
		b.turnsRemain = 0;
		BonusList bl;

		parser.endLine();

		parser.readString(); //ignore index
		loadStackExp(b, bl, parser);
		BOOST_FOREACH(Bonus * b, bl)
			addBonusForAllCreatures(b); //health bonus is common for all
		parser.endLine();

		for (int i = 1; i < 7; ++i)
		{
			for (int j = 0; j < 4; ++j) //four modifiers common for tiers
			{
				parser.readString(); //ignore index
				bl.clear();
				loadStackExp(b, bl, parser);
				BOOST_FOREACH(Bonus * b, bl)
					addBonusForTier(i, b);
				parser.endLine();
			}
		}
		for (int j = 0; j < 4; ++j) //tier 7
		{
			parser.readString(); //ignore index
			bl.clear();
			loadStackExp(b, bl, parser);
			BOOST_FOREACH(Bonus * b, bl)
			{
				addBonusForTier(7, b);
				creaturesOfLevel[0].addNewBonus(b); //bonuses from level 7 are given to high-level creatures
			}
			parser.endLine();
		}
//-----------------------------------------------
// CSLinkEffectOffensive updateOffensive
//-----------------------------------------------
bool CSLinkEffectOffensive::updateOffensive(CTimerEvent * event, bool sendReportForXP)
{
	if ( CSLinkEffect::update(event,true) )
		return true;

	CEntityBase * target = CEntityBaseManager::getEntityBasePtr( _TargetRowId );
	if ( !target )
	{
		nlwarning("<CSLinkEffectDot update> Invalid target %u",_TargetRowId.getIndex() );
		_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
		return true;
	}

	// if target is now protected, cancel the effect
	CSEffect *effect = target->lookForActiveEffect(EFFECT_FAMILIES::PowerAntiMagicShield);
	if (effect)
	{
		_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
		return true;
	}

	// test target is still valid for a link (can happen in PVP or duel)
	string errorCode;
	if ( !PHRASE_UTILITIES::validateSpellTarget(_CreatorRowId, _TargetRowId, ACTNATURE::OFFENSIVE_MAGIC, errorCode, true ) )
	{
		_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
		return true;
	}

	if (_LinkExists)
	{
		CEntityBase * caster = CEntityBaseManager::getEntityBasePtr( _CreatorRowId );
		if ( !caster )
		{
			nlwarning("<CSLinkEffectDot update> Invalid caster %u",_CreatorRowId.getIndex() );
			_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
			return true;
		}
	
		// test resistance
		if ( !_FirstResist && !EntitiesNoResist)
		{
			uint32 resistValue = 0;
			if (_Family == EFFECT_FAMILIES::Dot)
			{
				CSLinkEffectDot *dot = dynamic_cast<CSLinkEffectDot*> (this);
				if (dot)
				{
					resistValue = target->getMagicResistance(dot->getDamageType());
				}
			}
			else
			{
				resistValue = target->getMagicResistance(_Family);
			}

			sint skillValue = 0;
			if ( caster->getId().getType() == RYZOMID::player )
			{
				CCharacter * pC = (CCharacter *) caster;
				skillValue = pC->getSkillValue( _Skill );
			}
			else
			{
				const CStaticCreatures * form = caster->getForm();
				if ( !form )
				{
					nlwarning( "<MAGIC>invalid creature form %s in entity %s", caster->getType().toString().c_str(), caster->getId().toString().c_str() );
					_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
					return true;
				}	
				skillValue = form->getAttackLevel();
			}

			const CSEffect* debuff = caster->lookForActiveEffect( EFFECT_FAMILIES::DebuffSkillMagic );
			if ( debuff )
				skillValue -= debuff->getParamValue();
			const CSEffect * outPostBuff = caster->lookForActiveEffect( EFFECT_FAMILIES::OutpostMagic );
			if ( outPostBuff )
				skillValue += outPostBuff->getParamValue();

			// cap skill values with brick power
			if ( (sint32)_Power < skillValue )
				skillValue = (sint32)_Power;
			
			if ( caster->getId().getType() == RYZOMID::player )
			{
				CCharacter * pC = dynamic_cast<CCharacter *>( caster );
				if( pC )
				{
					// boost magic skill for low level chars
					sint sb = (sint)MagicSkillStartValue.get();
					skillValue = max( sb, skillValue );

					// add magic boost from consumable
					skillValue += pC->magicSuccessModifier();
				}
			}

			// test resistance
			const uint8 roll = (uint8)RandomGenerator.rand( 99 );
			_ResistFactor = CStaticSuccessTable::getSuccessFactor(SUCCESS_TABLE_TYPE::MagicResistLink, skillValue - resistValue, roll);

			// increase target resistance
			if (_ResistFactor > 0.0f)
			{
				if (_Family == EFFECT_FAMILIES::Dot)
				{
					CSLinkEffectDot *dot = dynamic_cast<CSLinkEffectDot*> (this);
					if (dot)
					{
						target->incResistModifier(dot->getDamageType(), _ResistFactor);
					}
				}
				else
				{
					target->incResistModifier(_Family,_ResistFactor);
				}
			}

			// delta level for XP gain 
			// opponent must be a creature or an npc to gain xp
			_Report.DeltaLvl = skillValue - resistValue;
			if (target->getId().getType() != RYZOMID::player && caster->getId().getType() == RYZOMID::player)
			{
				CCreature *creature = dynamic_cast<CCreature*> (target);
				if (!creature)
				{
					nlwarning("Entity %s type is creature but dynamic_cast in CCreature * returns NULL ?!", target->getId().toString().c_str());
					_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
					return true;
				}
				CCharacter * pC = dynamic_cast<CCharacter*> (caster);
				if (!pC)
				{
					nlwarning("Entity %s type is player but dynamic_cast in CCharacter * returns NULL ?!", caster->getId().toString().c_str());
					_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
					return true;
				}

				const CStaticCreatures* form = creature->getForm();
				if (form)
					_Report.DeltaLvl =  pC->getSkillValue(_Skill) - form->getXPLevel();
				else
					sendReportForXP = false;
			}
			else
				sendReportForXP = false;
		}
		else
		{
			_FirstResist = false;
			_ResistFactor = 1.0f;
		}
		
		bool end = true;
		// resist if factor <= 0
		if ( _ResistFactor > 0.0f  )
		{
			end = false;
			if ( _ResistFactor > 1.0f )
			{
				_ResistFactor = 1.0f;
			}

			// send report for XP			
			_Report.factor = _ResistFactor;

			if (sendReportForXP)
			{
				PROGRESSIONPVE::CCharacterProgressionPVE::getInstance()->actionReport( _Report );
				PROGRESSIONPVP::CCharacterProgressionPVP::getInstance()->reportAction(_Report);
			}
		}
		else
		{
			PHRASE_UTILITIES::sendSpellResistMessages( _CreatorRowId, _TargetRowId);
		}

		//////////////////////////////////////////////////////////////////////////
		// TEMPORARY : SEND AGGRO MESSAGE FOR EVERY UPDATE OF OFFENSIVE LINKS
		//////////////////////////////////////////////////////////////////////////	
		CAiEventReport report;
		report.Originator = _CreatorRowId;
		report.Target = _TargetRowId;
		report.Type = ACTNATURE::OFFENSIVE_MAGIC;		
		report.AggroAdd = -0.01f;
		CPhraseManager::getInstance().addAiEventReport(report);
		//////////////////////////////////////////////////////////////////////////
				
		if (end)
		{
			_EndTimer.setRemaining(1, new CEndEffectTimerEvent(this));
			return true;
		}
	}
	else
	{
		// no link -> no possible resist ?
	}

	return false;
} // CSLinkEffectOffensive::updateOffensive //
//--------------------------------------------------------------
//				CNpcBotDescription ::callback()  
//--------------------------------------------------------------
//void CNpcBotDescriptionImp::callback(const string &serviceName, uint8 sid)
void CGenNpcDescMsgImp::callback (const std::string &serviceName, NLNET::TServiceId sid)
{
	H_AUTO(CGenNpcDescMsgImp_callback );
	
	if ( ! Mirror.mirrorIsReady() )
	{
		nlwarning("<CNpcBotDescriptionImp::callback> Received from %s service but mirror not yet ready", serviceName.c_str() );
		return;
	}
	CEntityId	Eid= getEntityIdFromRow(_EntityIndex);
	if ( Eid.isUnknownId() )
	{
		nlwarning( "Received CNpcBotDescription with E%u that has no entity id, skipping it", _EntityIndex.getIndex() );
		nldebug( "Reason: %s", TheDataset.explainIsAccessible(_EntityIndex).c_str() );
#ifdef NL_DEBUG
//		nlstop;
#endif
		return;
	}
	CCreature *creature = CreatureManager.getCreature( Eid );
	if( creature == 0 )
	{
		creature = new CCreature();
		if ( creature )
		{
			creature->setAIGroupAlias( _GrpAlias );
			creature->setUserModelId(_UserModelId);
			creature->setCustomLootTableId(_CustomLootTableId);
			creature->setPrimAlias(_PrimAlias);
			if ( _GrpAlias != CAIAliasTranslator::Invalid )
			{
				CreatureManager.addNpcToGroup( _GrpAlias, _Alias ); // called every time the callback is received
			}
			creature->setId(Eid);
			creature->mirrorizeEntityState( false,	_EntityIndex ); // import the position
			creature->addPropertiesToMirror( _EntityIndex, false ); // init properties + import the sheetid from the mirror
			creature->setServerSheet();

			if( creature->getType() == CSheetId::Unknown )
			{
				nlwarning("<CNpcBotDescriptionImp::callback> Npc Eid %s GrpAlias %s Alias %s have invalide sheet, not spawned in EGS", 
					Eid.toString().c_str(), 
					CPrimitivesParser::aliasToString(_GrpAlias).c_str(), 
					CPrimitivesParser::aliasToString(_Alias).c_str() );
				delete creature;
				return;
			}
			else
			{
				creature->loadSheetCreature( _EntityIndex );
				
				//if the creature has a user model and if the user model's script contains parse errors, change
				//the creature's name to <usermodelId:ERROR> 
				if (_UserModelId != "" && CDynamicSheetManager::getInstance()->scriptErrors(_PrimAlias, _UserModelId) == true)
				{
					TDataSetRow row = creature->getEntityRowId();
					ucstring name;
					name.fromUtf8("<"+ _UserModelId + ":ERROR>");
					NLNET::CMessage	msgout("CHARACTER_NAME");
					msgout.serial(row);
					msgout.serial(name);
					sendMessageViaMirror("IOS", msgout);
				}
				CreatureManager.addCreature( Eid, creature );

				// set the items
				creature->setItems( _RightHandItem, _RightHandItemQuality, _LeftHandItem, _LeftHandItemQuality );
			}
		}
	}
//	else
//		CreatureManager.addUnaffectedDescription( *this );

	if (creature != NULL)
	{
		if (!creature->getCustomLootTableId().empty())
		{
			creature->getContextualProperty().directAccessForStructMembers().lootable(true);
		}
		creature->setBotDescription( *this );
		CAIAliasTranslator::getInstance()->updateAssociation(_Alias,Eid);

		if (_BuildingBot)
			COutpostManager::getInstance().onBuildingSpawned(creature);
	}
}
Exemplo n.º 15
0
		bool CRenderManager::update()
		{
			glColor3f(1.0f,1.0f,1.0f);

			// get camera
			CCamera *camera = CV_GAME_MANAGER->getControlManager()->getCamera();

			// transform view
			camera->transformView();			

			// Draw the map and items that fall into view frustum. 								

			// 1. extract approximate logical location of camera in the level map.
			vector2i center = CConversions::realToLogical(camera->getPosition());

			GLint centerX = center[0];
			GLint centerY = center[1];

			bool isFPS = CV_GAME_MANAGER->getControlManager()->isFPS();

			if (isFPS)
			{
				// fog only in FPS mode
				glEnable(GL_FOG);
			}

			/*
				In FPS mode we can't use height to determine visible offset. 
				We have to use some extent read from config (CV_CAMERA_FPS_EXTENT).
			*/
			GLint diff = (GLint)(isFPS?cameraFPSExtent:camera->getPosition()[1]*10.0f);

			// 2. create a bounding square making its center logical position calculate above.
			GLint minX = (centerX-diff>=0?centerX-diff:0);
			GLint minY = (centerY-diff>=0?centerY-diff:0);
			GLint maxX = (centerX+diff<(GLint)CV_LEVEL_MAP_SIZE?centerX+diff:CV_LEVEL_MAP_SIZE-1);
			GLint maxY = (centerY+diff<(GLint)CV_LEVEL_MAP_SIZE?centerY+diff:CV_LEVEL_MAP_SIZE-1);			

			// 3. go through all block that fall into this bounding square and check if they fall
			//    int out view frustum. If not then just exclude them.

			CBlock *block;

			GLint	blockVisible = 0,
					allVerticesCount = 0,
					creaturesVisible = 0,
					maxVertInput = 0,
					maxTexInput  = 0;

			tmpVboVertexBufferSize = 0;
			tmpVboTexCoordBufferSize = 0;

			vector3f	vertA,
						vertB,
						vertC;

			GLfloat **verts,
					*texCoords;

			CLevelManager			*lManager = CV_GAME_MANAGER->getLevelManager();
			CAnimatedTerrainManager	*atManager = CV_GAME_MANAGER->getAnimatedTerrainManager();
			CFrustum				*frustum = CV_GAME_MANAGER->getControlManager()->getViewFrustum();

			bool lavaWater = false;

			GLfloat delta = CV_GAME_MANAGER->getDeltaTime();	

			renderedBlocks.clear();

			for (GLint y=minY; y<=maxY; y++)
			{
				for (GLint x=minX; x<=maxX; x++)
				{
					block = lManager->getBlock(x,y);

					if (block)
					{
						//block->getBoundingBox()->draw(); // just for testing
						if (frustum->containsBBOX(block->getBoundingBox()))
						{
							blockVisible++;

							block->updateTexture(delta);

							lavaWater = (block->isLava() || block->isWater());

							if (lavaWater)
							{
								atManager->updateBlock(block);
							}

							renderedBlocks.push_back(block);

							// draw block objects
							if (block->getBlockObjects()->size()>0)
							{
								for (std::vector<CBlockObject*>::iterator rmIter = block->getBlockObjects()->begin(); rmIter != block->getBlockObjects()->end(); rmIter++)
								{
									CBlockObject *bObj = *rmIter;

									bObj->moveTo();
									glRotatef(bObj->getRotateY(),0.0f,1.0f,0.0f);
									bObj->drawModel(delta);
									glRotatef(-bObj->getRotateY(),0.0f,1.0f,0.0f);
									bObj->moveBack();
								}
							}

							bool isRoom = block->isRoom();

							if (isRoom)
							{
								std::vector<GLuint> *dls = block->getDisplayLists();
								if (dls->size()!=0)
								{			
									glEnable(GL_TEXTURE_2D);
									glBindTexture(GL_TEXTURE_2D,textureAtlasColor);
									glBegin(GL_QUADS);
									{
										for (std::vector<GLuint>::iterator dlIter = dls->begin(); dlIter != dls->end(); dlIter++)
										{
											glCallList(*dlIter);									
										}
									}
									glEnd();
									glDisable(GL_TEXTURE_2D);									
								}
							}							

							for (GLint f=CBlock::BFS_FRONT; f<=CBlock::BFS_CEILING; f++)
							{
								if ((!isFPS && f==CBlock::BFS_CEILING) || (isFPS && f==CBlock::BFS_TOP) || (isRoom && f!=CBlock::BFS_CEILING))
								{
									continue;
								}

								if (block->isFaceVisible((CBlock::BLOCK_FACE_SELECTOR)f))
								{		
									verts = block->getVertices();
									texCoords = block->getTextureCoordinates((CBlock::BLOCK_FACE_SELECTOR)f);

									if (lavaWater && f<=CBlock::BFS_RIGHT)
									{
										/* 
											Lava and water have only lowers row of wall sections drawn. 
											If they are drawn at all.
										*/
										maxVertInput = CV_FBLR_W_L_FACE_VERT_FLOATS;
										maxTexInput = CV_FBLR_W_L_FACE_TEX_FLOATS;
									}
									else
									{
										maxVertInput = f>=CBlock::BFS_TOP?CV_TBWLC_FACE_VERT_FLOATS:CV_FBLR_FACE_VERT_FLOATS;
										maxTexInput = f>=CBlock::BFS_TOP?CV_TBWLC_FACE_TEX_FLOATS:CV_FBLR_FACE_TEX_FLOATS;
									}

									if (tmpVboVertexBufferSize+maxVertInput>CV_MAX_VERTEX_BUFFER*3)
									{		
										vbo->setElementsCount(CVBO::IDT_vertex,tmpVboVertexBufferSize/3);
										vbo->setElementsCount(CVBO::IDT_texture0,tmpVboTexCoordBufferSize/2);
										vbo->setElementsCount(CVBO::IDT_texture1,tmpVboTexCoordBufferSize/2);
										vbo->draw();
										allVerticesCount+=tmpVboVertexBufferSize;
										tmpVboVertexBufferSize=0;
										tmpVboTexCoordBufferSize=0;						
									}

									memcpy(tmpVboVertexBuffer+tmpVboVertexBufferSize, verts[f], sizeof(GLfloat)*maxVertInput);
									tmpVboVertexBufferSize+=maxVertInput;

									memcpy(tmpVboTexCoordBuffer+tmpVboTexCoordBufferSize, texCoords, sizeof(GLfloat)*maxTexInput);						
									tmpVboTexCoordBufferSize+=maxTexInput;
																	
								}
							}
						}
					}
				}
			}

			if (tmpVboVertexBufferSize>0)
			{		
				vbo->setElementsCount(CVBO::IDT_vertex,tmpVboVertexBufferSize/3);
				vbo->setElementsCount(CVBO::IDT_texture0,tmpVboTexCoordBufferSize/2);
				vbo->setElementsCount(CVBO::IDT_texture1,tmpVboTexCoordBufferSize/2);
				vbo->draw();
				allVerticesCount+=tmpVboVertexBufferSize;
			}	

			// draw creatures
			CCreatureManager *cManager = CV_GAME_MANAGER->getCreatureManager();
			GLint cCount = cManager->getCreatureVector()->size();
			if (cCount>0)
			{		
				CCreature *creature = NULL;
				for (std::vector<CCreature*>::iterator cIter = cManager->getCreatureVector()->begin(); cIter != cManager->getCreatureVector()->end(); cIter++)
				{
					creature = (*cIter);

					if (creature)
					{
						sBoundingBox *cBBOX = creature->getModel()->getBoundingBox();
						cBBOX->translate(creature->getPosition());
						if (frustum->containsBBOX(cBBOX))
						{
							creature->draw(delta);
							creaturesVisible++;
						}
						cBBOX->translate(-creature->getPosition());
					}
				}
			}

			// draw transparent block objects
			for (std::vector<CBlock*>::iterator vbIter = renderedBlocks.begin(); vbIter != renderedBlocks.end(); vbIter++)
			{
				block = *vbIter;
				if (block->getBlockObjects()->size()>0)
				{
					for (std::vector<CBlockObject*>::iterator rmIter = block->getBlockObjects()->begin(); rmIter != block->getBlockObjects()->end(); rmIter++)
					{
						CBlockObject *bObj = *rmIter;

						bObj->moveTo();
						glRotatef(bObj->getRotateY(),0.0f,1.0f,0.0f);
						bObj->drawEffect();
						glRotatef(-bObj->getRotateY(),0.0f,1.0f,0.0f);
						bObj->moveBack();
					}
				}
			}

			glDisable(GL_FOG);
			
			if (!isFPS)
			{
				handlePickedObjects();
			}

			CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15*3),"Visible blocks: %d",blockVisible);
			CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15*2),"Visible creatures: %d",creaturesVisible);
			CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15),"Triangles drawn: %d",(allVerticesCount/4)*2);

			// render the lights representations. usefull for debugging
			CV_GAME_MANAGER->getLightingManager()->drawLightSources(frustum);
            
			return true;
		}