bool BattleManagerScreen::GetVecBetween( ICastEntity* from, ICastEntity* to, kmVec2& distVec ) { CastWorldModel* world = CastWorldModel::get(); if( !world->isValid(from) || !world->isValid(to) ) return false; kmVec2 pFrom; pFrom.x = pFrom.y = 0; GameEntityView* fromView = getViewForEntity(from); if( fromView != NULL ) { pFrom.x = fromView->getPositionX(); pFrom.y = fromView->getPositionY(); } kmVec2 pTo; pTo.x = pTo.y = 0; GameEntityView* toView = getViewForEntity(to); if( toView != NULL ) { pTo.x = toView->getPositionX(); pTo.y = toView->getPositionY(); }else { CCLog("uhoh.."); } kmVec2Subtract( &distVec, &pFrom, &pTo ); kmVec2Scale(&distVec, &distVec, GAME_UNIT_CONVERSION ); //safe to operate on same vector return true; }
void CastCommandState::spawnChannelEffects() { //CCLog("spawn channel tick effect"); //spawn effects CastTarget* target = m_iOwner->getTarget(); target->validateTargets(); for( int i=0; i< m_pModel->getNumEffectsOnChannel(); i++ ) { CastEffect* effect = new CastEffect( ); effect->init(this, i, m_iOwner, true ); //TODO: send all effects as one array so only one "packet" has to travel CastWorldModel* world = CastWorldModel::get(); world->addEffectInTransit(m_iOwner, effect, m_iOwner->getTarget(), CastCommandTime::get()); } }
void CastEffect::doEffect() { CastWorldModel* world = CastWorldModel::get(); if( ! world->isValid( m_pTarget ) ) return; if( m_startTime == 0 ) m_startTime = CastCommandTime::get(); Json::Value json = getDescriptor(); if( json.isMember("react") ) { m_pTarget->handleEffectReaction( json["react"], this ); } CCLog("on tick %d", m_numTicksCompleted); switch( m_type ) { case CET_DAMAGE_STAT: m_pTarget->incProperty( m_targetStat, -1* m_value ); break; case CET_HEAL_STAT: m_pTarget->incProperty( m_targetStat, m_value ); break; case CET_SUPPRESS_STAT: m_pTarget->startBuffProperty( m_targetStat, -1* m_value, this ); CCLog("cast at %f - lifetime %f", CastCommandTime::get(), m_lifeTime ); CastCommandScheduler::get()->scheduleSelector( schedule_selector(CastEffect::onTick), this, m_lifeTime, 0, 0.0f, false); break; case CET_BUFF_STAT: m_pTarget->startBuffProperty( m_targetStat, m_value, this ); CastCommandScheduler::get()->scheduleSelector( schedule_selector(CastEffect::onTick), this, m_lifeTime, 0, 0.0f, false); break; default: CCLOG("TODO: handle effect type"); } //check for return effect if( json.isMember("returnEffect") ) { json = json["returnEffect"]; //validate if( ! world->isValid( m_pOrigin ) ) return; CastEffect* bounce = new CastEffect(); bounce->initReturnEffect(this); bounce->m_value = m_value; //swap direction ICastEntity* from = m_pTarget; ICastEntity* to = m_pOrigin; CastTarget* ghostTarget = new CastTarget(); ghostTarget->addTargetEntity(to); world->addEffectInTransit(from, bounce, ghostTarget, CastCommandTime::get()); CC_SAFE_RELEASE_NULL(ghostTarget); } }
void CastCommandState::onCastComplete() { if( m_state != CCS_CASTING ) return; CastWorldModel* world = CastWorldModel::get(); if( !world->isValid( m_iOwner ) ) return; //check for cost (but dont apply it yet) if( m_costVal != 0 ) { float res = m_iOwner->getProperty( m_costStat ); //checking cost>0 so that if a tricky user wants cost to be 'negative' to 'add' value // we can do that even if it is below resource (ex: cost = increased heat) if( m_costVal > 0 && m_costVal > res ) { //not enough of resource to cast spell, so abort //todo: send aborted cast because of no resource CCLog("CCS: could not pay %f of %s to cast, aborting", m_costVal, m_costStat.c_str() ); onCooldownStart(); return; } } double currTime = CastCommandTime::get(); m_timeStart = currTime; //spawn effects CastTarget* target = m_iOwner->getTarget(); //target->validateTargets(); bool hasTargetInRange = target->hasTargetsAtRangeFromEntity(m_pModel->getRange(), m_iOwner); if(!hasTargetInRange) { CCLOG("CCS: no targets in range on cast of %s", m_pModel->getName().c_str() ); onCooldownStart(); return; } bool foundTarget = false; //ensure we actually reach at least one target for( int i=0; i< m_pModel->getNumEffectsOnCast(); i++ ) { //TODO: check for range //world->getPhysicsInterface()->GetVecBetween( m_iOwner, CastEffect* effect = new CastEffect( ); effect->init(this, i, m_iOwner, false ); //TODO: send all effects as one array so only one "packet" has to travel? //[Optimisation] world->addEffectInTransit(m_iOwner, effect, m_iOwner->getTarget(), CastCommandTime::get()); foundTarget = true; } if( foundTarget && m_costVal != 0 ) { //apply cost m_iOwner->incProperty( m_costStat, -1*m_costVal, NULL ); } if( m_pModel->channelTime > 0.0f ) { //begin channeling m_state = CCS_CHANNELING; int numTicks = (m_pModel->channelTime / m_pModel->channelFreq) + 1; CastCommandScheduler::get()->scheduleSelector( schedule_selector(CastCommandState::onSchedulerTick), this, m_pModel->channelFreq, numTicks, 0.0f, false); }else { //CCLog("Cast %s complete!", m_pModel->getName().c_str()); onCooldownStart(); } }