//---------------------------------------------------------------------------- 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(); } } } }
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, ®ion , &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; }
/** * 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] ); } } } }
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; } }
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); } }
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; }