void Start::findAreaUnits() { areaUnits.clear(); Area* area = player->getArea(); for (unsigned int i = 0; i < area->getNumZones(); i++) { Zone* zone = area->getZone(i); if (zone->isFilled()) { for (int k = 0; k < zone->getHeight(); k++) { for (int j = 0; j < zone->getWidth(); j++) { Location* loc = zone->getLocationAt(Coord(j, k)); if (loc->hasUnit()) { areaUnits.insert(std::pair<Unit*, Zone*>(loc->unit, zone)); } } } } } }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 BloodyWall::execute(Vampire* pVampire, ZoneCoord_t X, ZoneCoord_t Y, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); // Knowledge of Blood 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); 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) { decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1); // 이펙트의 지속시간을 계산한다. SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); 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.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION )!=NULL ) continue; // 현재 타일에다 이펙트를 추가할 수 있다면... 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(pVampire->getName()); pEffect->setCasterID(pVampire->getObjectID()); pEffect->setClan(Creature::CREATURE_CLASS_VAMPIRE, pVampire->getClanType()); pEffect->setDamage(output.Damage); pEffect->setDeadline(output.Duration); pEffect->setLevel(pVampire->getINT()); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); 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() ) && !checkZoneLevelToHitTarget(pTargetCreature ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } // pEffect->affect(pTarget); } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Dir); _GCSkillToTileOK2.setObjectID(pVampire->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(pVampire->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(pVampire->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, pVampire)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pVampire); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pVampire); // watcherList에서 cList에 속하지 않고, caster(pVampire)를 볼 수 없는 경우는 // 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, pVampire) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "BloodyWall : 왓처 리스트가 PC가 아닙니다." << endl; GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(getSkillType()); pVampire->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); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void TurnUndead::execute(Slayer * pSlayer, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; // Slayer Object Assertion Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Zone* pZone = pSlayer->getZone(); Assert(pZone != NULL); Player* pPlayer = pSlayer->getPlayer(); Assert(pPlayer != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = 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); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // calculate damage and duration time SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); bool bHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; if (oX == 0 && oY == 0 ) continue; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); // 타일에 있는 크리처들을 리스트로 만든다. list<Creature*> targetList; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); targetList.push_back(pCreature); } if(tile.hasCreature(Creature::MOVE_MODE_FLYING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_FLYING); targetList.push_back(pCreature); } if(tile.hasCreature(Creature::MOVE_MODE_BURROWING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_BURROWING); targetList.push_back(pCreature); } list<Creature*>::iterator itr = targetList.begin(); for (; itr != targetList.end(); itr++ ) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); if(checkZoneLevelToHitTarget(pTargetCreature ) && !pTargetCreature->isSlayer() && !pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) && canAttack(pSlayer, pTargetCreature ) ) { if(pTargetCreature->isVampire() || pTargetCreature->isOusters()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); bHit = true; // 데미지를 적용시킨다. GCModifyInformation gcMI; ::setDamage(pTargetCreature, output.Damage, pSlayer, pSkillSlot->getSkillType(), &gcMI); // HP 가 변했다고 당사자에게 보낸다. pTargetPlayer->sendPacket(&gcMI); GCSkillToObjectOK2 gcSkillToObjectOK2; gcSkillToObjectOK2.setObjectID(1); // 의미 없다. gcSkillToObjectOK2.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK2.setDuration(0); } else if(pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); bHit = true; ::setDamage(pMonster, output.Damage, pSlayer, pSkillSlot->getSkillType()); pMonster->addEnemy(pSlayer); } else { continue; } if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; GCSkillToObjectOK4 gcSkillToObjectOK4; gcSkillToObjectOK4.setTargetObjectID(pTargetCreature->getObjectID()); gcSkillToObjectOK4.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK4.setDuration(0); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcSkillToObjectOK4); // 성향을 올린다. increaseAlignment(pSlayer, pTargetCreature, _GCSkillToSelfOK1); } } } if(bHit) { //cout << "Skill Succesfully Attacked(" << output.Damage << ")" << endl; shareAttrExp(pSlayer, output.Damage, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); } // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(0); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(0); // 기술을 사용한 사람에게 packet 전달 pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); // 기술 delay setting 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 BloodyBreaker::execute(Vampire* pVampire, ZoneCoord_t X, ZoneCoord_t Y, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; SkillType_t SkillType = getSkillType(); // Knowledge of Blood 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } try { SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); Dir_t Dir = getDirectionToPosition(pVampire->getX(), pVampire->getY(), X, Y); // 강제로 knockback시킬 확률 // bool bForceKnockback = rand()%100 < output.ToHit; Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2); if (!rect.ptInRect(X, Y )) { executeSkillFailException(pVampire, SkillType); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; // GCSkillToTileOK3 _GCSkillToTileOK3; // GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; // GCSkillToTileOK6 _GCSkillToTileOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange()); if (bManaCheck && bTimeCheck && bRangeCheck ) { // 마나를 떨어뜨린다. decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1); // 좌표와 방향을 구한다. ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); list<Creature*> cList; // knockback 때문에 recursive 하게 데미지를 먹는 경우가 있다. // 그래서 제일 먼쪽에 있는 마스크부터 체크한다. for (int i = 21; i >= 0; i-- ) { int tileX = myX + m_pBloodyBreakerMask[Dir][i].x; int tileY = myY + m_pBloodyBreakerMask[Dir][i].y; // 현재 타일이 존 내부이고, 안전지대가 아니라면 맞을 가능성이 있다. if (rect.ptInRect(tileX, tileY)) { // 타일을 받아온다. Tile& tile = pZone->getTile(tileX, tileY); list<Creature*> targetList; if (tile.hasCreature(Creature::MOVE_MODE_WALKING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); targetList.push_back(pCreature); } if (tile.hasCreature(Creature::MOVE_MODE_FLYING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_FLYING); targetList.push_back(pCreature); } if (tile.hasCreature(Creature::MOVE_MODE_BURROWING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_BURROWING); targetList.push_back(pCreature); } list<Creature*>::iterator itr = targetList.begin(); for(; itr != targetList.end(); itr++) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); if (!canAttack(pVampire, pTargetCreature ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) ) { continue; } if (pTargetCreature != pVampire) { bool bPK = verifyPK(pVampire, pTargetCreature); bool bRaceCheck = pTargetCreature->isSlayer() || pTargetCreature->isMonster() || pTargetCreature->isOusters(); bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature); bool bHitRoll = false;//HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); int EnemyLevel = 0; if (pTargetCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature); EnemyLevel = pSlayer->getHighestSkillDomainLevel(); } else if (pTargetCreature->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pTargetCreature); EnemyLevel = pOusters->getLevel(); } else if (pTargetCreature->isMonster() ) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); EnemyLevel = pMonster->getLevel(); } // min : 20, max : 100 int hitRatio = max(20, 50 + pVampire->getLevel() - EnemyLevel + HitBonus); bHitRoll = (rand()%100) < hitRatio; if (bPK && bRaceCheck && bZoneLevelCheck && bHitRoll) { Damage_t Damage = 0; bool bForceKnockback = rand() & 1; Damage += computeMagicDamage(pTargetCreature, output.Damage, SkillType, true, pVampire); ObjectID_t targetObjectID = pTargetCreature->getObjectID(); cList.push_back(pTargetCreature); _GCSkillToTileOK1.addCListElement(targetObjectID); _GCSkillToTileOK2.addCListElement(targetObjectID); _GCSkillToTileOK5.addCListElement(targetObjectID); // 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다. setDamage(pTargetCreature, Damage, pVampire, SkillType, NULL, &_GCSkillToTileOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, NULL, &_GCSkillToTileOK1); increaseAlignment(pVampire, pTargetCreature, _GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bForceKnockback) { knockbackCreature(pZone, pTargetCreature, pVampire->getX(), pVampire->getY()); } if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, KILL_EXP); shareVampExp(pVampire, exp, _GCSkillToTileOK1); } } } } } } // 공격자의 아이템 내구성을 떨어뜨린다. decreaseDurability(pVampire, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(0); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK2.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); _GCSkillToTileOK5.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); pPlayer->sendPacket(&_GCSkillToTileOK1); // 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다. for (list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature * pTargetCreature = *itr; Assert(pTargetCreature != NULL); if (pTargetCreature->isPC()) { _GCSkillToTileOK2.clearList(); // HP의 변경사항을 패킷에다 기록한다. HP_t targetHP = 0; if (pTargetCreature->isSlayer()) { targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(ATTR_CURRENT); } else if (pTargetCreature->isVampire()) { targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(ATTR_CURRENT); } else if (pTargetCreature->isOusters()) { targetHP = (dynamic_cast<Ousters*>(pTargetCreature))->getHP(ATTR_CURRENT); } _GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP); // 아이템의 내구력을 떨어뜨린다. decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2); // 패킷을 보내준다. pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); } else if (pTargetCreature->isMonster()) { // 당근 적으로 인식한다. Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pVampire); } } cList.push_back(pVampire); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList); // set Next Run Time pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, SkillType, NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, SkillType); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void Darkness::execute(Vampire* pVampire, ZoneCoord_t X, ZoneCoord_t Y, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); // Knowledge of Innate 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_INNATE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_INNATE); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); bool bSlayerSafeZone = pZone->getZoneLevel(X, Y ) & SLAYER_SAFE_ZONE; 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 && !bSlayerSafeZone) { decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1); // 이펙트의 지속시간을 계산한다. SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // Wisdom of Darkness 이 있다면 지속시간 30% 증가 if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_WISDOM_OF_DARKNESS ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_WISDOM_OF_DARKNESS); Assert(pRankBonus != NULL); output.Duration += getPercentValue(output.Duration, pRankBonus->getPoint()); } Range_t Range = 3; int oX, oY; list<Creature*> cList; // denier list int edge = 1; // Wide Darkness 이 있다면 범위가 5*5 로 수정. skill type 을 수정한다. if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_WIDE_DARKNESS ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_WIDE_DARKNESS); Assert(pRankBonus != NULL); Range = pRankBonus->getPoint(); edge = (pRankBonus->getPoint() - 1 ) / 2; SkillType = SKILL_DARKNESS_WIDE; } // map<int, uint> canAddMap; for(oY = -edge; oY <= edge; oY++) for(oX = -edge; oX <= edge; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // if (canAddMap[normalizeCoord_DARKNESS(oX, oY, edge )] == 1 ) continue; if (tile.hasItem() ) { Item* pItem = tile.getItem(); if (pItem != NULL && pItem->getItemClass() == Item::ITEM_CLASS_CORPSE && pItem->getItemType() == MONSTER_CORPSE ) { MonsterCorpse* pMonsterCorpse = dynamic_cast<MonsterCorpse*>(pItem); if (g_pFlagManager->isFlagPole(pMonsterCorpse ) ) { // canAddMap[normalizeCoord_DARKNESS(oX+1, oY, edge )] = 1; // canAddMap[normalizeCoord_DARKNESS(oX+1, oY+1, edge )] = 1; // canAddMap[normalizeCoord_DARKNESS(oX, oY+1, edge )] = 1; continue; } } } if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION ) != NULL ) continue; // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 머시 그라운드 있음 추가 못한당. if (tile.getEffect(Effect::EFFECT_CLASS_MERCY_GROUND) != NULL ) continue; if (tile.getEffect(Effect::EFFECT_CLASS_DARKNESS_FORBIDDEN) != NULL ) continue; // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_DARKNESS); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectDarkness* pEffect = new EffectDarkness(pZone , tileX, tileY); pEffect->setDeadline(output.Duration); pEffect->setLevel(pVampire->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); 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->affectObject(pTarget, false); } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); _GCSkillToTileOK2.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, DARKNESS_SIGHT); _GCSkillToTileOK3.setObjectID(pVampire->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(pVampire->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, DARKNESS_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pVampire)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pVampire); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pVampire); // watcherList에서 cList에 속하지 않고, caster(pVampire)를 볼 수 없는 경우는 // 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, pVampire) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "Darkness : 왓처 리스트가 PC가 아닙니다." << endl; GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(getSkillType()); pVampire->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); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////// // // Visible::execute() // ////////////////////////////////////////////////////////////////////// void Visible::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를 받아온다. Player * pPlayer = pSlayer->getPlayer(); // Zone을 받아온다. Zone * pZone = pSlayer->getZone(); SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 기술의 레벨을 받아온다. //SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); //SkillDomainType_t DomainType = pSkillInfo->getDomainType(); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()); bool bHit = false; // 기술성공률 검증. if (bManaCheck && bTimeCheck && bRangeCheck) { SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; Coord_t myX = pSlayer->getX(), myY = pSlayer->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); list<Creature*> cList; int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); Creature * pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if(pTargetCreature != NULL) { if(pTargetCreature->isPC()) { bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_INVISIBILITY); if(bHitRoll && bEffected ) { // 주위에 GCAddXXX를 보내고, effect manager에서 effect를 삭제하고, GCRemoveEffect를 보낸다. addVisibleCreature(pZone, pTargetCreature, true); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); Player * pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); cList.push_back(pTargetCreature); bHit = true; } } } // if(pTargetCreature!= NULL) } decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); // EXP UP! Exp_t Point = pSkillInfo->getPoint(); if(bHit ) { shareAttrExp(pSlayer, Point, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(0); _GCSkillToTileOK4.setRange(dir); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); // Send Packet pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); 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 EffectPlasmaRocketLauncher::affect(Creature* pCreature) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG Assert(pCreature != NULL); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); Creature* pAttacker = pZone->getCreature(m_UserObjectID); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); int cX = pCreature->getX(); int cY = pCreature->getY(); for(int x = -1; x <= 1; x++) { for(int y= -1; y <= 1; y++) { int X = cX + x; int Y = cY + y; if(!rect.ptInRect(X, Y)) continue; Tile& tile = pZone->getTile(X, Y); const list<Object*>& oList = tile.getObjectList(); list<Object*>::const_iterator itr = oList.begin(); for(; itr != oList.end(); itr++) { Assert(*itr != NULL); Object* pObject = *itr; Assert(pObject != NULL); if(pObject->getObjectClass() == Object::OBJECT_CLASS_CREATURE) { Creature* pCreature2 = dynamic_cast<Creature*>(pObject); Assert(pCreature2 != NULL); if (pCreature2 != pCreature && pCreature2->isSlayer() ) continue; if (!(pZone->getZoneLevel() & COMPLETE_SAFE_ZONE) && !pCreature2->isDead() && !pCreature2->isFlag(Effect::EFFECT_CLASS_COMA) // 무적상태 체크. by sigi. 2002.9.5 && canAttack(pAttacker, pCreature2 ) ) { GCModifyInformation gcMI, gcAttackerMI; setDamage(pCreature2, m_Point, pAttacker, SKILL_PLASMA_ROCKET_LAUNCHER, &gcMI, &gcAttackerMI); if (pCreature2->isPC() ) pCreature2->getPlayer()->sendPacket(&gcMI); if (pAttacker!=NULL) { computeAlignmentChange(pCreature2, m_Point, pAttacker, &gcMI, &gcAttackerMI); if (pAttacker->isPC() ) { if (pAttacker->isSlayer() && !pCreature2->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pAttacker); if (pSlayer != NULL ) { GCModifyInformation gcMI; shareAttrExp(pSlayer, m_Point, 1, 8, 1, gcAttackerMI); } } if (pAttacker->isPC() ) pAttacker->getPlayer()->sendPacket(&gcAttackerMI); } } } } } } } setDeadline(0); __END_DEBUG __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 EnergyDrop::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; EffectEnergyDrop * pEffect = NULL; EffectEnergyDrop * pEffect2 = NULL; try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = SKILL_ENERGY_DROP; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pMonster->getX(); ZoneCoord_t myY = pMonster->getY(); bool bRangeCheck = verifyDistance(pMonster, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pMonster, 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 (bRangeCheck && bHitRoll && bTileCheck) { // calculate damage and duration time SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); Range_t Range = 3; // 기존에 같은 이펙트가 타일에 있다면 지우고 새로 설정한다. Tile& tile = pZone->getTile(X, Y); Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_ENERGY_DROP); if(pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성해서 타일에 붙인다. pEffect = new EffectEnergyDrop(pZone, X, Y); pEffect->setDeadline(output.Duration); pEffect->setNextTime(0); pEffect->setTick(output.Tick); pEffect->setDamage(output.Damage); pEffect->setLevel(pSkillInfo->getLevel()/2); // //ObjectRegistry& objectregister = pZone->getObjectRegistry(); //objectregister.registerObject(pEffect); // // //pZone->addEffect(pEffect); //tile.addEffect(pEffect); // 이펙트 오브젝트를 생성해서 타일에 붙인다. pEffect2 = new EffectEnergyDrop(pZone, X, Y); pEffect2->setDeadline(output.Duration); pEffect2->setNextTime(0); pEffect2->setTick(output.Tick); pEffect2->setDamage(output.Damage * 30 / 100); pEffect2->setLevel(pSkillInfo->getLevel()/2); // 이펙트 범위내의 모든 Creature에게 effect를 붙여준다. // Slayer가 기술을 사용한 경우 같은 Slayer에게는 // 해당하지 않는다. bool bEffected = false; Creature* pTargetCreature; list<Creature*> cList; cList.push_back(pMonster); int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; EffectEnergyDrop * pTempEffect = NULL; if(oX == 2 || oX == -2 || oY == 2 || oY == -2 ) pTempEffect = pEffect2; else pTempEffect = pEffect; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); if (!tile.canAddEffect()) continue; pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if(pTargetCreature != NULL) { if(pTargetCreature->isPC()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { Player* pTargetPlayer = pTargetCreature->getPlayer(); bEffected = true; bool bCanSee = canSee(pTargetCreature, pMonster); _GCSkillToTileOK1.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); cList.push_back(pTargetCreature); if (bCanSee) { // 공격을 당한 사람에게 _GCSkillToTileOK2.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); } } } } // if(pTargetCreature!= NULL) } // 기술을 쓴 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(myX); _GCSkillToTileOK3.setY(myY); //_GCSkillToTileOK3.setDuration(output.Duration); //_GCSkillToTileOK3.setRange(Range); // 기술을 당한 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setRange(Range); //기술을 쓴 사람과 당한 사람을 모두 볼 수 있는 사람들에게 _GCSkillToTileOK5.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setRange(Range); // 기술을 쓸 사람과 당한 사람을 모두 볼 수 있는 사람들에게 broadcasing cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); // 기술을 쓴 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3, cList); // 기술을 당한 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4, cList); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); } catch(Throwable& t) { SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 // 뱀파이어가 Energy Drop Skill을 Tile에 사용했을때 사용하는 Handler ////////////////////////////////////////////////////////////////////////////// void EnergyDrop::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; EffectEnergyDrop * pEffect = NULL; EffectEnergyDrop * pEffect2 = 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); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); 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()); 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)) { Tile& tile = pZone->getTile(X, Y); if (tile.canAddEffect()) bTileCheck = true; } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); // calculate damage and duration time SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // Holy Smashing 이 있다면 데미지 10% 증가 if (pSlayer->hasRankBonus(RankBonus::RANK_BONUS_HOLY_SMASHING ) ) { RankBonus* pRankBonus = pSlayer->getRankBonus(RankBonus::RANK_BONUS_HOLY_SMASHING); Assert(pRankBonus != NULL); output.Damage += pRankBonus->getPoint(); } Range_t Range = 3; // 기존에 같은 이펙트가 타일에 있다면 지우고 새로 설정한다. Tile& tile = pZone->getTile(X, Y); Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_ENERGY_DROP); if(pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성해서 타일에 붙인다. //cout << "make EffectObject to Tile" << X << " " << Y << endl; pEffect = new EffectEnergyDrop(pZone, X, Y); pEffect->setUserObjectID(pSlayer->getObjectID()); // pEffect->setCasterName(pSlayer->getName()); // pEffect->setPartyID(pSlayer->getPartyID()); pEffect->setDeadline(output.Duration); pEffect->setNextTime(0); pEffect->setTick(output.Tick); pEffect->setDamage(output.Damage); pEffect->setLevel(pSkillInfo->getLevel()/2); // //ObjectRegistry& objectregister = pZone->getObjectRegistry(); //objectregister.registerObject(pEffect); // // //pZone->addEffect(pEffect); //tile.addEffect(pEffect); // 이펙트 오브젝트를 생성해서 타일에 붙인다. pEffect2 = new EffectEnergyDrop(pZone, X, Y); pEffect2->setUserObjectID(pSlayer->getObjectID()); pEffect2->setDeadline(output.Duration); pEffect2->setNextTime(0); pEffect2->setTick(output.Tick); pEffect2->setDamage(output.Damage * 30 / 100); pEffect2->setLevel(pSkillInfo->getLevel()/2); // 이펙트 범위내의 모든 Creature에게 effect를 붙여준다. // Slayer가 기술을 사용한 경우 같은 Slayer에게는 // 해당하지 않는다. bool bEffected = false; bool bHit = false; Creature* pTargetCreature; list<Creature*> cList; cList.push_back(pSlayer); int oX, oY; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); if (!tile.canAddEffect()) continue; pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); EffectEnergyDrop * pTempEffect = NULL; if(oX == 2 || oX == -2 || oY == 2 || oY == -2 ) pTempEffect = pEffect2; else pTempEffect = pEffect; if(pTargetCreature != NULL && canAttack(pSlayer, pTargetCreature )) { if(pTargetCreature->isVampire()||pTargetCreature->isOusters()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { //cout << "EnergyDrop to Slayer Success" << endl; Player* pTargetPlayer = pTargetCreature->getPlayer(); bEffected = true; bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; bool bCanSee = canSee(pTargetCreature, pSlayer); _GCSkillToTileOK1.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); cList.push_back(pTargetCreature); if (bCanSee) { // 공격을 당한 사람에게 _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); } } else { //cout << "EnergyDrop to Vampire fail" << endl; } } else if(pTargetCreature->isMonster()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { //cout << "EnergyDrop to Monster Success" << endl; bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); // 마지막 때린 애가 슬레이어라고 설정한다. by sigi. 2002.6.21 pMonster->setLastHitCreatureClass(Creature::CREATURE_CLASS_SLAYER); } else { //cout << "EnergyDrop to Monster Falis" << endl; } } } // if(pTargetCreature!= NULL) } if(bHit) { //cout << "Skill Succesfully Attacked(" << output.Damage << ")" << endl; shareAttrExp(pSlayer, output.Damage, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } // 기술을 사용한 사람들에게 _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); // 기술을 쓴 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); //_GCSkillToTileOK3.setDuration(output.Duration); //_GCSkillToTileOK3.setRange(Range); // 기술을 당한 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setRange(Range); //기술을 쓴 사람과 당한 사람을 모두 볼 수 있는 사람들에게 _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setRange(Range); // 기술을 사용한 사람에게 packet 전달 pPlayer->sendPacket(&_GCSkillToTileOK1); // 기술을 쓸 사람과 당한 사람을 모두 볼 수 있는 사람들에게 broadcasing // broadcasting후 5번OK를 받은 사람을 기록한다. // 여기에 기록된 사람은 차후 broadcasting에서 제외된다. cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); // 기술을 쓴 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3, cList); // 기술을 당한 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4, cList); // 기술 delay setting pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); } catch(Throwable& t) { SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << 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 Mephisto::execute(Vampire* pVampire) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pVampire != NULL); if(!pVampire->hasSkill(SKILL_MEPHISTO) ) return; try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); int oX, oY; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); for(oX = -4; oX <= 4; oX++) for(oY = -4; oY <= 4; oY++) { int tileX = myX+oX; int tileY = myY+oY; if (!rect.ptInRect(tileX, tileY)) continue; // 타일 위에! 뱀파이어가 있는지 본다! Tile& tile = pZone->getTile(tileX, tileY); Creature * pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if(pTargetCreature != NULL && pTargetCreature != pVampire && pTargetCreature->isVampire() ) { bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_MEPHISTO); if(bEffected ) continue; Vampire* pTargetVampire= dynamic_cast<Vampire*>(pTargetCreature); // 스킬 레벨에 따라 데미지 보너스가 달라진다. SkillInput input(pVampire); SkillOutput output; input.SkillLevel = pVampire->getSTR()+pVampire->getDEX()+pVampire->getINT(); input.DomainLevel = pVampire->getLevel(); computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectMephisto* pEffect = new EffectMephisto(pTargetVampire); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pTargetVampire->addEffect(pEffect); pTargetVampire->setFlag(Effect::EFFECT_CLASS_MEPHISTO); // 이로 인하여 바뀌는 능력치를 보낸다. VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); pTargetVampire->sendRealWearingInfo(); pTargetVampire->sendModifyInfo(prev); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Assert(false); } // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetVampire->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MEPHISTO); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetVampire->getX(), pTargetVampire->getY(), &gcAddEffect); } } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << 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 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 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 DuplicateSelf::execute(Monster* pMonster) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; //cout << "DuplicateSelf" << endl; MonsterType_t MType = pMonster->getMonsterType(); map<MonsterType_t, MonsterType_t>::const_iterator itr = m_DuplicateMonsterTypes.find(MType); // 분신할 MonsterType이 없으면 분신 모하지.. if (itr==m_DuplicateMonsterTypes.end()) { //cout <<"DuplicateSelf::noMonsterType: " << (int)MType << endl; return; } MonsterType_t DuplicateMType = itr->second; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE)) { //cout << "DuplicateSelf: hide" << endl; return; } if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pMonster, true); } //GCSkillToSelfOK2 _GCSkillToSelfOK2; ZoneCoord_t x = pMonster->getX(); ZoneCoord_t y = pMonster->getY(); bool bRangeCheck = checkZoneLevelToUseSkill(pMonster); //bool bMoveModeCheck = pMonster->isWalking(); if (bRangeCheck)// && bMoveModeCheck) { //cout << "DuplicateSelf OK" << endl; GCSkillToTileOK5 _GCSkillToTileOK5; _GCSkillToTileOK5.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK5.setSkillType(getSkillType()); _GCSkillToTileOK5.setX(x); _GCSkillToTileOK5.setY(y); _GCSkillToTileOK5.setDuration( 0); pZone->broadcastPacket(x, y, &_GCSkillToTileOK5); //-------------------------------------------------------- // 주위에 knockback되는맞는 애들을 체크해준다. //-------------------------------------------------------- //SkillInput input(pMonster); //SkillOutput output; //computeOutput(input, output); // 몬스터를 존에 추가한다. SUMMON_INFO summonInfo; summonInfo.scanEnemy = true; summonInfo.hasItem = false; summonInfo.initHPPercent = pMonster->getHP(ATTR_CURRENT)*100/pMonster->getHP(ATTR_MAX); int numFake = min((1+rand()%3), pMonster->getINT()/100); //cout << "numDuplicate = " << numFake<< endl; MonsterManager* pMonsterManager = pZone->getMonsterManager(); Assert(pMonsterManager != NULL); list<Monster*> summonedMonsters; for (int i=0; i<numFake; i++) { int X = max(0, min((int)pZone->getWidth()-1, (x - 5 + rand()%11))); int Y = max(0, min((int)pZone->getHeight()-1, (y - 5 + rand()%11))); try { pMonsterManager->addMonsters(X, Y, DuplicateMType, 1, summonInfo, &summonedMonsters); } catch (Throwable& t) { cerr << t.toString() << endl; } } // 잔상을 보여준다. list<Monster*>::const_iterator iMonster = summonedMonsters.begin(); for (; iMonster!=summonedMonsters.end(); iMonster++) { Monster* pFakeMonster = *iMonster; GCFakeMove gcFakeMove; gcFakeMove.setObjectID(pMonster->getObjectID()); gcFakeMove.setXY(pFakeMonster->getX(), pFakeMonster->getY()); pZone->broadcastPacket(x, y, &gcFakeMove); } // 괜히 몬스터도 어딘가로 이동해본다. // 50번 시도.. for (int i=0; i<50; i++) { int X = max(0, min((int)pZone->getWidth()-1, (x - 8 + rand()%11))); int Y = max(0, min((int)pZone->getHeight()-1, (y - 8 + rand()%11))); if (pZone->moveFastMonster(pMonster, x,y, X,Y, getSkillType())) { break; } } } else { //cout << "RangeCheckFailed" << endl; executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////// // // ThunderFlash::execute() // ////////////////////////////////////////////////////////////////////// void ThunderFlash::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); // 무장하고 있는 무기가 널이거나, SWORD가 아니라면 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_SWORD) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end" << endl; return; } bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK5 _GCSkillToTileOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()); // 마나가 있어야 하고, 시간과 거리 체크에 성공하고, if (bManaCheck && bTimeCheck && bRangeCheck) { // MP를 떨어뜨린다. decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); // 좌표와 방향을 구한다. ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Damage_t SkillDamage = output.Damage; Damage_t Damage = 0; bool bHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2); list<Creature*> cList; for (int count=0; count<4; count++) { int tileX = X + m_pThunderFlashMask[count].x; int tileY = Y + m_pThunderFlashMask[count].y; // 현재 타일이 존 내부이고, 안전지대가 아니라면, 맞을 확률이 있다. if (rect.ptInRect(tileX, tileY)) { // 타일을 받아온다. Tile& tile = pZone->getTile(tileX, tileY); list<Creature*> targetList; if (tile.hasCreature(Creature::MOVE_MODE_WALKING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); targetList.push_back(pCreature); } list<Creature*>::iterator itr = targetList.begin(); for(; itr != targetList.end(); itr++) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); bool bMoveModeCheck = (pTargetCreature->getMoveMode() == Creature::MOVE_MODE_WALKING) ? true : false; bool bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel/2); //bool bCanHit = canHit(pSlayer, pTargetCreature, SkillType); bool bCanHit = true; bool bPK = verifyPK(pSlayer, pTargetCreature); bool bRaceCheck = pTargetCreature->isSlayer() || pTargetCreature->isNPC(); bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature); if (bMoveModeCheck && bHitRoll && bCanHit && bPK && !bRaceCheck && bZoneLevelCheck) { CheckCrossCounter(pSlayer, pTargetCreature, Damage, pSkillInfo->getRange()); bool bCriticalHit = false; Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit) + SkillDamage; ObjectID_t targetObjectID = pTargetCreature->getObjectID(); cList.push_back(pTargetCreature); _GCSkillToTileOK1.addCListElement(targetObjectID); _GCSkillToTileOK2.addCListElement(targetObjectID); _GCSkillToTileOK5.addCListElement(targetObjectID); // 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다. setDamage(pTargetCreature, Damage, pSlayer, SkillType, NULL, &_GCSkillToTileOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, NULL, &_GCSkillToTileOK1); increaseAlignment(pSlayer, pTargetCreature, _GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } // 슬레이어가 아닐 경우에만 맞은 것으로 간주한다. if (!pTargetCreature->isSlayer()) { bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; } } } //for (; itr != objectList.end(); itr++) } // if (rect.ptInRect(tileX, tileY) && ... } // for (int count=0; count<3; count++) if (bHit) { if (bIncreaseExp) { shareAttrExp(pSlayer, Damage , 8, 1, 1, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } } // 공격자 아이템 내구성 떨어트림. decreaseDurability(pSlayer, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); pPlayer->sendPacket(&_GCSkillToTileOK1); // 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다. for (list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature * pTargetCreature = *itr; Assert(pTargetCreature != NULL); if (pTargetCreature->isPC()) { _GCSkillToTileOK2.clearList(); // HP의 변경사항을 패킷에다 기록한다. HP_t targetHP = 0; if (pTargetCreature->isSlayer()) targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(ATTR_CURRENT); else if (pTargetCreature->isVampire()) targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(ATTR_CURRENT); _GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP); // 아이템의 내구력을 떨어뜨린다. decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2); // 패킷을 보내준다. pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); } else if (pTargetCreature->isMonster()) { // 당근 적으로 인식한다. Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } } cList.push_back(pSlayer); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList); // set Next Run Time 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 EffectSpiritGuard::affect(Creature* pCastCreature) throw(Error) { __BEGIN_TRY Assert(pCastCreature != NULL); if (!pCastCreature->isSlayer() ) return; Player* pPlayer = dynamic_cast<Player*>(pCastCreature->getPlayer()); Assert(pPlayer != NULL); Slayer* pSlayer = dynamic_cast<Slayer*>(pCastCreature); Assert(pSlayer != NULL); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SKILL_SPIRIT_GUARD); if (pSkillInfo == NULL ) { return; } GCModifyInformation gcAttackerMI; Zone* pZone = pCastCreature->getZone(); Assert(pZone != NULL); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); ZoneCoord_t Cx = pCastCreature->getX(); ZoneCoord_t Cy = pCastCreature->getY(); bool isHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; for (int x=-1; x<=1; x++ ) { for (int y=-1; y<=1; y++ ) { if (x == 0 && y == 0 ) continue; int X = Cx + x; int Y = Cy + y; if (!rect.ptInRect(X, Y ) ) continue; // 타일안에 존재하는 오브젝트를 가져온다. Tile& tile = pZone->getTile(X, Y); if(tile.hasCreature(Creature::MOVE_MODE_WALKING) ) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); Assert(pCreature != NULL); // 자신은 맞지 않는다. 무적도 안 맞는다. 슬레이어도 안 맞느다. // 안전지대 체크 // 2003.1.10 by bezz, Sequoia if (pCreature == m_pTarget || !canAttack(pCastCreature, pCreature ) || pCreature->isFlag(Effect::EFFECT_CLASS_COMA ) || pCreature->isSlayer() || pCreature->isNPC() || !checkZoneLevelToHitTarget(pCreature) ) { continue; } isHit = true; if (maxEnemyLevel < pCreature->getLevel() ) maxEnemyLevel = pCreature->getLevel(); EnemyNum++; if (pCreature->isVampire() || pCreature->isOusters() ) { // Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); GCModifyInformation gcMI; ::setDamage(pCreature, m_Damage, pCastCreature, SKILL_SPIRIT_GUARD, &gcMI, &gcAttackerMI); pCreature->getPlayer()->sendPacket(&gcMI); // 맞는 동작을 보여준다. GCSkillToObjectOK2 gcSkillToObjectOK2; gcSkillToObjectOK2.setObjectID(1); // 의미 없다. gcSkillToObjectOK2.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK2.setDuration(0); pCreature->getPlayer()->sendPacket(&gcSkillToObjectOK2); } else if (pCreature->isMonster() ) { Monster* pMonster = dynamic_cast<Monster*>(pCreature); ::setDamage(pMonster, m_Damage, pCastCreature, SKILL_SPIRIT_GUARD, NULL, &gcAttackerMI); pMonster->addEnemy(pCastCreature); } else Assert(false); GCSkillToObjectOK4 gcSkillToObjectOK4; gcSkillToObjectOK4.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK4.setTargetObjectID(pCreature->getObjectID()); gcSkillToObjectOK4.setDuration(0); pZone->broadcastPacket(X, Y, &gcSkillToObjectOK4, pCreature); } } } if (isHit ) { SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillSlot* pSkillSlot = pSlayer->getSkill(SKILL_SPIRIT_GUARD); if (pSkillSlot != NULL ) { increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), gcAttackerMI, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, gcAttackerMI); } } setNextTime(m_Delay); __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void RefusalEther::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); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); // 이펙트의 지속시간을 계산한다. 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)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); list<Creature*> cList; for (int ox = X-output.Range; ox <= X+output.Range; ++ox ) for (int oy = Y-output.Range; oy <= Y+output.Range; ++oy ) { if (!rect.ptInRect(ox,oy) ) continue; Tile& rTile = pZone->getTile(ox,oy); EffectDarkness* pEffect = dynamic_cast<EffectDarkness*>(rTile.getEffect(Effect::EFFECT_CLASS_DARKNESS)); int ratio = 0; if (pEffect != NULL ) { if (input.SkillLevel <= 15 ) { ratio = (int)(pOusters->getLevel() + (input.SkillLevel * 8.0 / 3.0 ) - pEffect->getLevel()); } else { ratio = (int)(pOusters->getLevel() + 20 + (input.SkillLevel * 4.0 / 3.0 ) - pEffect->getLevel()); if (input.SkillLevel == 30 ) ratio = (int)(ratio * 1.1); } ratio = max(20, ratio); } else { continue; } bool bHitRoll2 = (rand()%100) < ratio; if (bHitRoll2) { pZone->deleteEffect(pEffect->getObjectID()); Creature* pTargetCreature = NULL; if (rTile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = rTile.getCreature(Creature::MOVE_MODE_WALKING); GCDeleteEffectFromTile gcDeleteEffectFromTile; gcDeleteEffectFromTile.setXY(ox, oy); gcDeleteEffectFromTile.setObjectID(pEffect->getObjectID()); gcDeleteEffectFromTile.setEffectID(Effect::EFFECT_CLASS_DARKNESS); pZone->broadcastPacket(ox, oy, &gcDeleteEffectFromTile); if (pTargetCreature != NULL && pTargetCreature->isPC() && pTargetCreature->getObjectID() != pOusters->getObjectID() ) cList.push_back(pTargetCreature); } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(0); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK2.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(0); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK2.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.setRange(0); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(0); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(0); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK6.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*>::iterator itr = cList.begin(); list<Creature*>::iterator endItr = cList.end(); for (; itr != endItr ; ++itr ) { if ((*itr)->isPC() ) { (*itr)->getPlayer()->sendPacket(&_GCSkillToTileOK2); } } cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); 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 << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void IceField::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); 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()); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); // 이펙트의 지속시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel(); 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)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int grade = 0; if (input.SkillLevel <= 10 ) grade = 0; else if (input.SkillLevel <= 20 ) grade = 1; else if (input.SkillLevel < 30 ) grade = 2; else grade = 3; list<Creature*> cList; // denier list for (int i=0; i<m_MaskNum[grade]; i++) { POINT& pt = m_IceFieldMask[grade][i]; int tileX = X+pt.x; int tileY = Y+pt.y; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_ICE_FIELD); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectIceField* pEffect = new EffectIceField(pZone , tileX, tileY); pEffect->setCasterName(pOusters->getName()); pEffect->setCasterID(pOusters->getObjectID()); pEffect->setDeadline(output.Duration); pEffect->setDuration(output.Range); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); 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->isVampire() ) && !checkZoneLevelToHitTarget(pTargetCreature ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } // pEffect->affect(pTarget); } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(grade); _GCSkillToTileOK2.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(grade); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(grade); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(grade); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(grade); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pOusters)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pOusters); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pOusters); // watcherList에서 cList에 속하지 않고, caster(pOusters)를 볼 수 없는 경우는 // 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, pOusters) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "IceField : 왓처 리스트가 PC가 아닙니다." << endl; // GCSkillFailed1 _GCSkillFailed1; // _GCSkillFailed1.setSkillType(getSkillType()); // pOusters->getPlayer()->sendPacket(&_GCSkillFailed1); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; // return; continue; } 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); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void Darkness::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_DARKNESS; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pMonster->getX(); ZoneCoord_t myY = pMonster->getY(); bool bRangeCheck = verifyDistance(pMonster, X, Y, pSkillInfo->getRange()); bool bHitRoll = 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; int oX, oY; list<Creature*> cList; // denier list 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.hasItem() ) { Item* pItem = tile.getItem(); if (pItem != NULL && pItem->getItemClass() == Item::ITEM_CLASS_CORPSE && pItem->getItemType() == MONSTER_CORPSE ) { MonsterCorpse* pMonsterCorpse = dynamic_cast<MonsterCorpse*>(pItem); if (g_pFlagManager->isFlagPole(pMonsterCorpse ) ) continue; } } // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 머시 그라운드 있음 추가 못한당. if (tile.getEffect(Effect::EFFECT_CLASS_MERCY_GROUND) != NULL ) continue; // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_DARKNESS); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectDarkness* pEffect = new EffectDarkness(pZone , tileX, tileY); pEffect->setDeadline(output.Duration); pEffect->setLevel(pMonster->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); 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->affectObject(pTarget, false); } } } } _GCSkillToTileOK2.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, DARKNESS_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(Range); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pMonster->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, DARKNESS_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 }