void EffectWithWarning::start() { setNextTime(m_SignDuration); setDeadline(m_SignDuration + m_MainDuration); GCAddEffectToTile gcAET; gcAET.setXY(m_X, m_Y); gcAET.setObjectID(getObjectID()); gcAET.setEffectID(m_SignEffect); gcAET.setDuration(m_SignDuration); m_pZone->broadcastPacket(m_X, m_Y, &gcAET); m_State = false; }
bool DynamicZoneGateOfAlter::openGateToAlter() { Assert(m_pZone != NULL); // 퀘스트를 진행시킨다. map<ObjectID_t, Creature*>::const_iterator itr = m_pZone->getPCManager()->getCreatures().begin(); map<ObjectID_t, Creature*>::const_iterator endItr = m_pZone->getPCManager()->getCreatures().end(); for (; itr != endItr; ++itr ) { Assert(itr->second != NULL); if (itr->second->isPC() ) { PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(itr->second); Assert(pPC != NULL); pPC->getGQuestManager()->clearDynamicZone(m_TemplateZoneID); } } // 포탈 위치를 찾아서 그 위에다 EffectTilePortal 을 보낸다. int tx = -1; int ty = -1; for (int x=0; x<m_pZone->getWidth(); x++) { for (int y=0; y<m_pZone->getHeight(); y++) { Tile& tile = m_pZone->getTile(x,y); if (tile.hasPortal()) { tx = x; ty = y; } } } if (tx != -1 ) { GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(Effect::EFFECT_CLASS_TILE_PORTAL); gcAddEffectToTile.setDuration(999999); gcAddEffectToTile.setXY(tx, ty); m_pZone->broadcastPacket(&gcAddEffectToTile); } return true; }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void IceWave::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE)) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pMonster, true); } int dx = (rand()%7)-3; int dy = (rand()%7)-3; X -= min((int)X, dx); Y -= min((int)Y, dy); if (X > pZone->getWidth() ) X = pZone->getWidth()-1; if (Y > pZone->getHeight() ) Y = pZone->getHeight()-1; pZone->moveFastMonster(pMonster, pMonster->getX(), pMonster->getY(), X, Y, getSkillType()); ZoneCoord_t x = pMonster->getX(); ZoneCoord_t y = pMonster->getY(); bool bRangeCheck = checkZoneLevelToUseSkill(pMonster); bool bMoveModeCheck = pMonster->isWalking(); if (bRangeCheck && bMoveModeCheck) { //-------------------------------------------------------- // 주위에 knockback되는맞는 애들을 체크해준다. //-------------------------------------------------------- SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_MAX; param.STRMultiplier = 0; param.DEXMultiplier = 0; param.INTMultiplier = 0; param.bMagicHitRoll = true; param.bMagicDamage = true; param.bAdd = false; SIMPLE_SKILL_OUTPUT result; for (int i=0; i<8; ++i ) { for (int j=0; j<3; ++j ) { int ox = pMonster->getX() + dirMoveMask[i].x * j * 3 + dirMoveMask[i].x * 2; int oy = pMonster->getY() + dirMoveMask[i].y * j * 3 + dirMoveMask[i].y * 2; GCAddEffectToTile gcAE; gcAE.setXY(ox, oy); gcAE.setEffectID(Effect::EFFECT_CLASS_ICICLE_AUGER_LARGE); gcAE.setDuration(15); pMonster->getZone()->broadcastPacket(ox, oy, &gcAE); } } for (int i=0; i<193; i++) { if ((abs((int)x - (int)m_pIceWaveMask[i].x) <= 2) && (abs((int)y - (int)m_pIceWaveMask[i].y) <= 2)) param.addMask(m_pIceWaveMask[i].x, m_pIceWaveMask[i].y, 80); else param.addMask(m_pIceWaveMask[i].x, m_pIceWaveMask[i].y, 100); } // 강제로 맞는 애들을 knockback 시킨다. bool bForceKnockback = false; g_SimpleTileMeleeSkill.execute(pMonster, x, y, param, result, 0, bForceKnockback); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void BloodyWall::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = SKILL_BLOODY_WALL; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pMonster->getX(); ZoneCoord_t myY = pMonster->getY(); // 마스터는 무조건~~ bool bRangeCheck = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif || verifyDistance(pMonster, X, Y, pSkillInfo->getRange()); bool bHitRoll = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif || HitRoll::isSuccessMagic(pMonster, pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bRangeCheck && bHitRoll && bTileCheck) { // 이펙트의 지속시간을 계산한다. SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); //Range_t Range = 3; Dir_t Dir = getDirectionToPosition(myX, myY, X, Y); list<Creature*> cList; // denier list for (int i=0; i<5; i++) { POINT& pt = m_BloodyWallMask[Dir][i]; int tileX = X+pt.x; int tileY = Y+pt.y; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_BLOODY_WALL); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectBloodyWall* pEffect = new EffectBloodyWall(pZone , tileX, tileY); pEffect->setCasterName(pMonster->getName()); pEffect->setCasterID(pMonster->getObjectID()); pEffect->setClan(Creature::CREATURE_CLASS_MONSTER, pMonster->getClanType()); pEffect->setDamage(output.Damage); pEffect->setDeadline(output.Duration); pEffect->setLevel(pMonster->getINT()); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAE; gcAE.setObjectID(pEffect->getObjectID()); gcAE.setEffectID(pEffect->getSendEffectClass()); gcAE.setDuration(output.Duration); gcAE.setXY(tileX, tileY); pZone->broadcastPacket(tileX, tileY, &gcAE); const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; Creature* pTargetCreature = NULL; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE && ((pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer() || pTargetCreature->isOusters() ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } //pEffect->affectObject(pTarget, false); } } } } _GCSkillToTileOK2.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Dir); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); _GCSkillToTileOK3.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Dir); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Dir); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Dir); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pMonster)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } cList.push_back(pMonster); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pMonster); // watcherList에서 cList에 속하지 않고, caster(pMonster)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pMonster) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void MagicElusion::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()) && checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagicElusion(pSlayer); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; // 이펙트의 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); Range_t Range = 2; int oX, oY; list<Creature*> cList; // denier list ObjectRegistry & objectregister = pZone->getObjectRegistry(); // 일단 이미 sanctuary가 있는지 검색한다. for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.canAddEffect()) { Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_MAGIC_ELUSION); // 이미 있다면 // 기술 실패다. if (pOldEffect != NULL) { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } } for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 이펙트 클래스를 생성한다. EffectMagicElusion* pEffect = new EffectMagicElusion(pZone , tileX, tileY); pEffect->setDeadline(output.Duration); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); if (oX==0 && oY==0) { pEffect->setBroadcastingEffect(true); GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(pEffect->getEffectClass()); gcAddEffectToTile.setObjectID(pEffect->getObjectID()); gcAddEffectToTile.setXY(X, Y); gcAddEffectToTile.setDuration(output.Duration); pZone->broadcastPacket(X, Y, &gcAddEffectToTile, pSlayer); } else { // 가운데 이펙트가 아니면 브로드캐스팅해주지 않는다. pEffect->setBroadcastingEffect(false); } const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE ) { Creature* pCreature = dynamic_cast<Creature*>(pTarget); Assert(pCreature != NULL); if (pCreature->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); GCModifyInformation gcMI; ::setDamage(pVampire, output.Damage, pSlayer, pSkillSlot->getSkillType(), &gcMI); pVampire->getPlayer()->sendPacket(&gcMI); cList.push_back(pCreature); } else if (pCreature->isMonster() ) { ::setDamage(pCreature, output.Damage, pSlayer, pSkillSlot->getSkillType()); } } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Range); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Range); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Range); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pSlayer)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pSlayer); // watcherList에서 cList에 속하지 않고, caster(pSlayer)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pSlayer) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (pWatcher->isPC()) { pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } if (bTimeCheck ) pSkillSlot->setRunTime(output.Delay); } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
void EffectContinualGroundAttack::affect() throw(Error) { __BEGIN_TRY Assert(m_pZone!=NULL); int creatureNum = m_pZone->getPCManager()->getSize() + m_pZone->getMonsterManager()->getSize(); // 부하를 조금이라도 줄이기 위해서.. // 존에 공격받을 캐릭터가 있어야지 effect를 붙이지.. if (creatureNum > 0) { // zone의 특정 위치에 effect를 출력하고 damage를 준다. int range = min(100, (m_MaxNumber-m_MinNumber)); // 동시에 1~100사이 int number = (range>0? m_MinNumber + rand()%range : m_MinNumber); VSRect rect(0, 0, m_pZone->getWidth()-1, m_pZone->getHeight()-1); // m_MinNumber ~ m_MaxNumber 개의 공격 for (int i=0; i<number; i++) { const BPOINT& pt = m_pZone->getRandomEmptyTilePosition(); if (!rect.ptInRect(pt.x, pt.y)) continue; // 중심 타일 체크 Tile& tile = m_pZone->getTile(pt.x, pt.y); int X = pt.x; int Y = pt.y; if (!tile.canAddEffect()) continue; int DamagePercent = 100; // 이펙트 오브젝트를 생성한다. Effect* pAttackEffect = NULL; switch (m_AttackEffect) { case EFFECT_CLASS_GROUND_ATTACK : { // 같은 이펙트가 이미 존재한다면 더 쎈 damage로 설정한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_GROUND_ATTACK); if (pOldEffect != NULL) { EffectGroundAttack* pGAEffect = dynamic_cast<EffectGroundAttack*>(pOldEffect); pGAEffect->setDamagePercent(max(DamagePercent, pGAEffect->getDamagePercent())); continue; } EffectGroundAttack* pEffect = new EffectGroundAttack(m_pZone, X, Y); pEffect->setDeadline(22); // 2초+알파 pEffect->setDamagePercent(DamagePercent); pAttackEffect = pEffect; } break; case EFFECT_CLASS_METEOR_STRIKE : { // 같은 이펙트가 있다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_METEOR_STRIKE); if (pOldEffect != NULL ) { ObjectID_t effectID = pOldEffect->getObjectID(); m_pZone->deleteEffect(effectID); } EffectMeteorStrike* pEffect = new EffectMeteorStrike(m_pZone, X, Y); pEffect->setDeadline(10); // 1초 // 400 ~ 600 100% // 200 ~ 300 50% // 100 ~ 150 25% pEffect->setDamage(400+rand()%200); pAttackEffect = pEffect; } break; default : break; } if (pAttackEffect!=NULL) { // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = m_pZone->getObjectRegistry(); objectregister.registerObject(pAttackEffect); // 존 및 타일에다가 이펙트를 추가한다. m_pZone->addEffect(pAttackEffect); tile.addEffect(pAttackEffect); // 가운데꺼만 이펙트를 보여준다. GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(pAttackEffect->getEffectClass()); gcAddEffectToTile.setObjectID(pAttackEffect->getObjectID()); gcAddEffectToTile.setXY(X, Y); gcAddEffectToTile.setDuration(20); // 2초 m_pZone->broadcastPacket(X, Y, &gcAddEffectToTile); } } } setNextTime(m_Delay); __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void SummonGroundElemental::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 데미지와 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); // if (rect.ptInRect(X, Y)) // { // Tile& tile = pZone->getTile(X, Y); // if (tile.canAddEffect()) bTileCheck = true; // } TPOINT pt = findSuitablePosition(pZone, X, Y, Creature::MOVE_MODE_WALKING); if (pt.x == -1 ) { bTileCheck = false; } else { bTileCheck = true; for (int oX = pt.x - 2 ; oX <= pt.x + 2 ; ++oX ) for (int oY = pt.y - 2 ; oY <= pt.y + 2 ; ++oY ) { if (!rect.ptInRect(oX, oY ) ) continue; if (pZone->getTile(oX, oY).getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA ) != NULL ) { bTileCheck = false; break; } } } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int oX, oY; /* HP = 200 + (S_level * 10) Defense = 50 + (S_level * 2) Protection = 20 + (S_level * 2) Poison Resistance = 70% Acid Resistance = 60% Curse Resistance = 100% Blood Resistance = 50% Regen = 1 HP per 1 sec */ Monster* pGroundElemental = new Monster(GROUND_ELEMENTAL_TYPE); pGroundElemental->setName("대지 정령"); pGroundElemental->setHP(1000 + input.SkillLevel * 100); pGroundElemental->setHP(1000 + input.SkillLevel * 100, ATTR_MAX); pGroundElemental->setDefense(0); pGroundElemental->setProtection(0); pGroundElemental->setResist(MAGIC_DOMAIN_POISON, 0); pGroundElemental->setResist(MAGIC_DOMAIN_ACID, 0); pGroundElemental->setResist(MAGIC_DOMAIN_CURSE, 0); pGroundElemental->setResist(MAGIC_DOMAIN_BLOOD, 0); pGroundElemental->setFlag(Effect::EFFECT_CLASS_IMMUNE_TO_CURSE); pGroundElemental->removeFlag(Effect::EFFECT_CLASS_HIDE); pGroundElemental->setMoveMode(Creature::MOVE_MODE_WALKING); // 무뇌정령 pGroundElemental->setBrain(NULL); pZone->addCreature(pGroundElemental, X, Y, 2); X = pGroundElemental->getX(); Y = pGroundElemental->getY(); //cout << pGroundElemental->toString() << " 을 " << X << ", " << Y << " 에 불러냈습니다." << endl; EffectGroundElemental* pCreatureEffect = new EffectGroundElemental(pGroundElemental); pCreatureEffect->setDeadline(output.Duration); pGroundElemental->setFlag(pCreatureEffect->getEffectClass()); pGroundElemental->addEffect(pCreatureEffect); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pGroundElemental->getObjectID()); gcAddEffect.setEffectID(pCreatureEffect->getSendEffectClass()); pZone->broadcastPacket(X, Y, &gcAddEffect); // addSimpleCreatureEffect(pGroundElemental, Effect::EFFECT_CLASS_GROUND_ELEMENTAL_CENTER); // for (int i = 0; i < m_MaskIndex[Grade]; ++i ) for (oX = X - 2 ; oX <= X + 2 ; ++oX ) for (oY = Y - 2 ; oY <= Y + 2 ; ++oY ) { // oX = m_ElementalMask[Grade][i].x; // oY = m_ElementalMask[Grade][i].y; if (!rect.ptInRect(oX, oY)) continue; if (oX == X && oY == Y ) continue; Tile& tile = pZone->getTile(oX, oY); if (!tile.canAddEffect()) continue; if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 같은 이펙트가 이미 존재한다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성한다. EffectSummonGroundElemental* pEffect = new EffectSummonGroundElemental(pZone, oX, oY); pEffect->setDeadline(output.Duration); // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); // 존 및 타일에다가 이펙트를 추가한다. pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAddEffect; gcAddEffect.setXY(oX, oY); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setObjectID(pEffect->getObjectID()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(oX, oY, &gcAddEffect); } ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*> cList; cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void SwordOfThor::execute(Slayer * pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY // cout << "(x,y)=" << X << "," << Y << endl; Zone* pZone = pSlayer->getZone(); Assert(pZone!=NULL); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_SWORD; param.STRMultiplier = 8; param.DEXMultiplier = 1; param.INTMultiplier = 1; param.bMagicHitRoll = false; param.bMagicDamage = false; param.bAdd = false; param.bExpForTotalDamage = false; for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { param.addMask(i, j, 100); } SIMPLE_SKILL_OUTPUT result; // 목표위치+4방향 /* param.addMask(0 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100);*/ g_SimpleTileMissileSkill.execute(pSlayer, X, Y, pSkillSlot, param, result); if (result.bSuccess ) { for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { ZoneCoord_t tx = X+i; ZoneCoord_t ty = Y+j; if (!isValidZoneCoord(pZone, tx, ty) ) continue; Tile& rTile = pZone->getTile(tx, ty); if (!rTile.canAddEffect() ) continue; EffectSwordOfThor* pEffect = new EffectSwordOfThor(pZone, tx, ty); pEffect->setLevel(input.SkillLevel); pEffect->setDeadline(output.Duration); pZone->registerObject(pEffect); if (i != 0 || j != 0 ) pEffect->setBroadcastingEffect(false); else { GCAddEffectToTile gcAE; gcAE.setEffectID(pEffect->getSendEffectClass()); gcAE.setXY(tx, ty); gcAE.setObjectID(pEffect->getObjectID()); gcAE.setDuration(output.Duration); pZone->broadcastPacket(tx, ty, &gcAE); // cout << tx << ", " << ty << " Effect broadcast" << endl; } pZone->addEffect(pEffect); rTile.addEffect(pEffect); // cout << tx << ", " << ty << " add Effect" << endl; } } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void Prominence::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 데미지와 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, output.Range); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) { Tile& tile = pZone->getTile(X, Y); if (tile.canAddEffect()) bTileCheck = true; } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int oX, oY; for (oX = X - 1 ; oX <= X + 1 ; ++oX ) for (oY = Y - 1 ; oY <= Y + 1 ; ++oY ) { if (!rect.ptInRect(oX, oY)) continue; Tile& tile = pZone->getTile(oX, oY); if (!tile.canAddEffect()) continue; // 머시 그라운드 있음 추가 못한당. if (tile.getEffect(Effect::EFFECT_CLASS_MERCY_GROUND) != NULL ) continue; if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 같은 이펙트가 이미 존재한다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_PROMINENCE); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } checkMine(pZone, oX, oY); // 이펙트 오브젝트를 생성한다. EffectProminence* pEffect = new EffectProminence(pZone, oX, oY); pEffect->setUserObjectID(pOusters->getObjectID()); pEffect->setDeadline(output.Duration); pEffect->setNextTime(0); pEffect->setTick(output.Tick); pEffect->setDamage(output.Damage); pEffect->setLevel(pOustersSkillSlot->getExpLevel()); if (Grade > 0 ) { if (Grade == 1 ) pEffect->setSendEffectClass(Effect::EFFECT_CLASS_PROMINENCE_2); else pEffect->setSendEffectClass(Effect::EFFECT_CLASS_PROMINENCE_3); } // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); // 존 및 타일에다가 이펙트를 추가한다. pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAddEffect; gcAddEffect.setXY(oX, oY); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setObjectID(pEffect->getObjectID()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(oX, oY, &gcAddEffect, pOusters); } ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*> cList; cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void Sanctuary::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()) && checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { // 이펙트의 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Range_t Range = 3; int oX, oY; list<Creature*> cList; // denier list ObjectRegistry & objectregister = pZone->getObjectRegistry(); // 일단 이미 sanctuary가 있는지 검색한다. for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.canAddEffect()) { Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_SANCTUARY); // 이미 있다면 // 기술 실패다. if (pOldEffect != NULL) { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } } // 실패하면 마나가 줄면 안 되므로 여기서 줄여준다. decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 현재 타일에다 이펙트를 추가할 수 있다면... //if (tile.canAddEffect()) // 위에서 체크했다. { // 같은 effect가 있으면 지운다. // 위에서 체크했다. /* Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_SANCTUARY); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } */ // 이펙트 클래스를 생성한다. EffectSanctuary* pEffect = new EffectSanctuary(pZone , tileX, tileY, X, Y); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSlayer->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); if (oX==0 && oY==0) { GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(pEffect->getEffectClass()); gcAddEffectToTile.setObjectID(pEffect->getObjectID()); gcAddEffectToTile.setXY(X, Y); gcAddEffectToTile.setDuration(output.Duration); pZone->broadcastPacket(X, Y, &gcAddEffectToTile, pSlayer); } const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; //Creature* pTargetCreature = NULL; //if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE) { // pTargetCreature = dynamic_cast<Creature*>(pTarget); // 이펙트 클래스를 생성한다. /* EffectSanctuary* pEffect = new EffectSanctuary(pZone , tileX, tileY, X, Y); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSlayer->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // 캐릭터에 붙는다. 못 움직이게 할려고.. objectregister.registerObject(pEffect); pTargetCreature->getEffectManager()->addEffect(pEffect); pZone->addEffect(pEffect); */ } /* && (pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer()) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); } */ pEffect->affectObject(pTarget, false); } } } } // client에서는 effect생성되는 시간이 있어서 // 타이밍 맞출려면.. 시간을 좀 빼줘야 한다. -_-; output.Duration -= 20; // 2초 뺀다. _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, SANCTUARY_SIGHT); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Range); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Range); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Range); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, SANCTUARY_SIGHT); // EXP UP! SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pSlayer)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pSlayer); // watcherList에서 cList에 속하지 않고, caster(pSlayer)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pSlayer) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "Sanctuary : 왓처 리스트가 PC가 아닙니다." << endl; GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(getSkillType()); pSlayer->getPlayer()->sendPacket(&_GCSkillFailed1); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void LandMineExplosion::execute(Monster* pMonster) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); //GCSkillToSelfOK2 _GCSkillToSelfOK2; ZoneCoord_t x = pMonster->getX(); ZoneCoord_t y = pMonster->getY(); bool bRangeCheck = checkZoneLevelToUseSkill(pMonster); if (bRangeCheck) { //-------------------------------------------------------- // 주위에 knockback되는맞는 애들을 체크해준다. //-------------------------------------------------------- SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_MAX; param.STRMultiplier = 0; param.DEXMultiplier = 0; param.INTMultiplier = 0; param.bMagicHitRoll = true; param.bMagicDamage = true; param.bAdd = false; SIMPLE_SKILL_OUTPUT result; for (int i=0; i<48; i++) { param.addMask(m_pLandMineExplosionMask[i].x, m_pLandMineExplosionMask[i].y, 100); } // 강제로 맞는 애들을 knockback 시킨다. // bool bForceKnockback = true; g_SimpleTileMeleeSkill.execute(pMonster, x, y, param, result, 0, false); GCAddEffectToTile gcAE; gcAE.setXY(x, y); gcAE.setEffectID(Effect::EFFECT_CLASS_LAND_MINE_EXPLOSION); gcAE.setObjectID(0); gcAE.setDuration(0); pZone->broadcastPacket(x, y, &gcAE); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }