void Monster::updateTargetList() { auto friendIterator = friendList.begin(); while (friendIterator != friendList.end()) { Creature* creature = *friendIterator; if (creature->getHealth() <= 0 || !canSee(creature->getPosition())) { creature->decrementReferenceCounter(); friendIterator = friendList.erase(friendIterator); } else { ++friendIterator; } } auto targetIterator = targetList.begin(); while (targetIterator != targetList.end()) { Creature* creature = *targetIterator; if (creature->getHealth() <= 0 || !canSee(creature->getPosition())) { creature->decrementReferenceCounter(); targetIterator = targetList.erase(targetIterator); } else { ++targetIterator; } } SpectatorHashSet spectators; g_game.map.getSpectators(spectators, position, true); spectators.erase(this); for (Creature* spectator : spectators) { if (canSee(spectator->getPosition())) { onCreatureFound(spectator); } } }
void Monster::updateTargetList() { CreatureList::iterator it = friendList.begin(); while(it != friendList.end()) { if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition())) { (*it)->releaseThing2(); it = friendList.erase(it); } else ++it; } it = targetList.begin(); while(it != targetList.end()) { if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition())) { (*it)->releaseThing2(); it = targetList.erase(it); } else ++it; } const SpectatorVec& list = g_game.getSpectators(getPosition()); for(SpectatorVec::const_iterator list_it = list.begin(), list_end = list.end(); list_it != list_end; ++list_it) { if((*list_it) != this && canSee((*list_it)->getPosition())) onCreatureFound(*list_it); } }
void Actor::updateTargetList() { CreatureList::iterator it; for(it = friendList.begin(); it != friendList.end();){ if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition())){ (*it)->unRef(); it = friendList.erase(it); } else ++it; } for(it = targetList.begin(); it != targetList.end();){ if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition())){ (*it)->unRef(); it = targetList.erase(it); } else ++it; } const SpectatorVec& list = g_game.getSpectators(getPosition()); for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it){ if((*it) != this && canSee((*it)->getPosition())){ onCreatureFound(*it); } } }
void Monster::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if(creature == this) { if(isSummon()) isMasterInRange = canSee(master->getPosition()); updateTargetList(); updateIdleStatus(); } else { bool canSeeNewPos = canSee(newPos), canSeeOldPos = canSee(oldPos); if(canSeeNewPos && !canSeeOldPos) onCreatureEnter(const_cast<Creature*>(creature)); else if(!canSeeNewPos && canSeeOldPos) onCreatureLeave(const_cast<Creature*>(creature)); if(isSummon() && master == creature && canSeeNewPos) //Turn the summon on again isMasterInRange = true; updateIdleStatus(); if(!followCreature && !isSummon() && isOpponent(creature)) //we have no target lets try pick this one selectTarget(const_cast<Creature*>(creature)); } }
void Actor::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if(creature == this){ if(isSummon()){ isMasterInRange = canSee(getMaster()->getPosition()); } updateTargetList(); updateIdleStatus(); /* TODO: Optimizations here if(teleport){ //do a full update of the friend/target list } else{ //partial update of the friend/target list } */ } else{ bool canSeeNewPos = canSee(newPos); bool canSeeOldPos = canSee(oldPos); if(canSeeNewPos && !canSeeOldPos){ onCreatureEnter(const_cast<Creature*>(creature)); } else if(!canSeeNewPos && canSeeOldPos){ onCreatureLeave(const_cast<Creature*>(creature)); } if(isSummon() && getMaster() == creature){ if(canSeeNewPos){ //Turn the summon on again isMasterInRange = true; } } updateIdleStatus(); if(!followCreature && !isSummon()){ //we have no target lets try pick this one if(isOpponent(creature)){ selectTarget(const_cast<Creature*>(creature)); } } } }
bool ZombieEntity::attack() { Vector2D playerPos = game().getPlayerPosition(); bool attacking = false; // left ? if (playerPos.x < x && playerPos.y > y - 15 && playerPos.y < y + 15 && canSee(playerPos.x, playerPos.y)) { direction = 3; velocity.x = -creatureSpeed; velocity.y = 0; facingDirection = 4; attacking = true; } // right ? else if (playerPos.x > x && playerPos.y > y - 15 && playerPos.y < y + 15 && canSee(playerPos.x, playerPos.y)) { direction = 1; velocity.x = creatureSpeed; velocity.y = 0; facingDirection = 6; attacking = true; } // down ? else if (playerPos.y > y && playerPos.x > x - 15 && playerPos.x < x + 15 && canSee(playerPos.x, playerPos.y)) { direction = 2; velocity.x = 0; velocity.y = creatureSpeed; facingDirection = 2; attacking = true; } // up ? else if (playerPos.y < y && playerPos.x > x - 15 && playerPos.x < x + 15 && canSee(playerPos.x, playerPos.y)) { direction = 0; velocity.x = 0; velocity.y = -creatureSpeed; facingDirection = 8; attacking = true; } if (attacking) { SoundManager::getInstance().playSound(SOUND_ZOMBIE_ATTACKING); facingTimer = 0.2f; nextFacingDirection = facingDirection; } return attacking; }
bool Creature::setAttackedCreature(Creature* creature) { if(creature) { const Position& creaturePos = creature->getPosition(); if(creaturePos.z != getPosition().z || !canSee(creaturePos)) { attackedCreature = NULL; return false; } } attackedCreature = creature; if(attackedCreature) { onTarget(attackedCreature); attackedCreature->onAttacked(); } for(std::list<Creature*>::iterator cit = summons.begin(); cit != summons.end(); ++cit) (*cit)->setAttackedCreature(creature); Condition* condition = getCondition(CONDITION_LOGINPROTECTION, CONDITIONID_DEFAULT); if(condition) removeCondition(condition); return true; }
void AISystem::basicAI(entityx::Entity &e) { world->currLevel->calculateMaps(); world->currLevel->computeMovesTo(target_x, target_y); if (canSee(e) && canMoveToward(e)) { moveToward(e); } // if (failMoraleCheck() && canMoveAway()) { // moveAway(); // } else if (hasRangedAttack() && canMoveToward(e)) { // if (decideToCharge()) { // moveToward(e); // } else { // rangedAttack(); // } // } else if (canAttack() && hasRangedAttack() && canMoveAway()) { // if (decideToRetreat()) { // moveAway(); // } else { // attack(); // } // } else if (canAttack()) { // attack(); // } else if (canMoveToward(e)) { // moveToward(e); // } else { // wait(); // } }
void ProtocolGameBase::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown) { auto result = knownCreatureSet.insert(id); if (!result.second) { known = true; return; } known = false; if (knownCreatureSet.size() > 1300) { // Look for a creature to remove for (std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin(), end = knownCreatureSet.end(); it != end; ++it) { Creature* creature = g_game.getCreatureByID(*it); if (!canSee(creature)) { removedKnown = *it; knownCreatureSet.erase(it); return; } } // Bad situation. Let's just remove anyone. std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin(); if (*it == id) { ++it; } removedKnown = *it; knownCreatureSet.erase(it); } else { removedKnown = 0; } }
bool Creature::setFollowCreature(Creature* creature, bool fullPathSearch /*= false*/) { if (creature) { if (followCreature == creature) { return true; } const Position& creaturePos = creature->getPosition(); if (creaturePos.z != getPosition().z || !canSee(creaturePos)) { followCreature = NULL; return false; } if (!listWalkDir.empty()) { listWalkDir.clear(); onWalkAborted(); } hasFollowPath = false; forceUpdateFollowPath = false; followCreature = creature; isUpdatingPath = true; } else { isUpdatingPath = false; followCreature = NULL; } onFollowCreature(creature); return true; }
void ProtocolGameBase::sendCreatureLight(const Creature* creature) { if (!canSee(creature)) { return; } NetworkMessage msg; AddCreatureLight(msg, creature); writeToOutputBuffer(msg); }
bool ProtocolGameBase::canSee(const Creature* c) const { if (!c || !player || c->isRemoved()) { return false; } if (!player->canSeeCreature(c)) { return false; } return canSee(c->getPosition()); }
void ProtocolGameBase::sendMagicEffect(const Position& pos, uint8_t type) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x83); msg.addPosition(pos); msg.addByte(type); writeToOutputBuffer(msg); }
void Monster::onCreatureAppear(const Creature* creature) { Creature::onCreatureAppear(creature); if(creature == this) { //We just spawned lets look around to see who is there. if(isSummon()) isMasterInRange = canSee(master->getPosition()); updateTargetList(); updateIdleStatus(); } else onCreatureEnter(const_cast<Creature*>(creature)); }
void Actor::onCreatureAppear(const Creature* creature, bool isLogin) { Creature::onCreatureAppear(creature, isLogin); if(creature == this){ //We just spawned lets look around to see who is there. if(isSummon()){ isMasterInRange = canSee(getMaster()->getPosition()); } updateTargetList(); updateIdleStatus(); } else{ onCreatureEnter(const_cast<Creature*>(creature)); } }
void Monster::update() { if (canDie && isDead()) { return; } engine.map->computeFOV(*this); if (canSee(engine.player->x, engine.player->y)) { moveCount = TRACKING_TURNS; } else { --moveCount; } if (moveCount > 0) { moveOrAttack(engine.player->x, engine.player->y); } }
void Monster::onCreatureAppear(Creature* creature, bool isLogin) { Creature::onCreatureAppear(creature, isLogin); if (mType->info.creatureAppearEvent != -1) { // onCreatureAppear(self, creature) LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { std::cout << "[Error - Monster::onCreatureAppear] Call stack overflow" << std::endl; return; } ScriptEnvironment* env = scriptInterface->getScriptEnv(); env->setScriptId(mType->info.creatureAppearEvent, scriptInterface); lua_State* L = scriptInterface->getLuaState(); scriptInterface->pushFunction(mType->info.creatureAppearEvent); LuaScriptInterface::pushUserdata<Monster>(L, this); LuaScriptInterface::setMetatable(L, -1, "Monster"); LuaScriptInterface::pushUserdata<Creature>(L, creature); LuaScriptInterface::setCreatureMetatable(L, -1, creature); if (scriptInterface->callFunction(2)) { return; } } if (creature == this) { //We just spawned lets look around to see who is there. if (isSummon()) { isMasterInRange = canSee(getMaster()->getPosition()); } updateTargetList(); updateIdleStatus(); } else { onCreatureEnter(creature); } }
bool Creature::setAttackedCreature(Creature* creature) { if (creature) { const Position& creaturePos = creature->getPosition(); if (creaturePos.z != getPosition().z || !canSee(creaturePos)) { attackedCreature = NULL; return false; } attackedCreature = creature; onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } else { attackedCreature = NULL; } for (Creature* summon : summons) { summon->setAttackedCreature(creature); } return true; }
void ProtocolGameBase::sendUpdateTile(const Tile* tile, const Position& pos) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x69); msg.addPosition(pos); if (tile) { GetTileDescription(tile, msg); msg.addByte(0x00); msg.addByte(0xFF); } else { msg.addByte(0x01); msg.addByte(0xFF); } writeToOutputBuffer(msg); }
void Monster::onCreatureAppear(const Creature* creature) { Creature::onCreatureAppear(creature); if(creature == this) { //We just spawned lets look around to see who is there. if(isSummon()) isMasterInRange = canSee(getMaster()->getPosition()); setStorage(510, mType->realName); // sistema de shiny nomes 2.0 CreatureEventList spawn = getCreatureEvents(CREATURE_EVENT_SPAWN); for(CreatureEventList::iterator it = spawn.begin(); it != spawn.end(); ++it) (*it)->executeOnSpawn(this); updateTargetList(); updateIdleStatus(); } else onCreatureEnter(const_cast<Creature*>(creature)); }
bool Creature::setAttackedCreature(Creature* creature) { if(creature){ const Position& creaturePos = creature->getPosition(); if(creaturePos.z != getPosition().z || !canSee(creaturePos)){ attackedCreature = NULL; return false; } } attackedCreature = creature; if(attackedCreature){ onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } std::list<Creature*>::iterator cit; for(cit = summons.begin(); cit != summons.end(); ++cit) { (*cit)->setAttackedCreature(creature); } return true; }
bool Creature::canSee(const Position& pos) const { return canSee(getPosition(), pos, Map::maxViewportX, Map::maxViewportY); }
void Creature::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) { if (creature == this) { lastStep = OTSYS_TIME(); lastStepCost = 1; if (!teleport) { if (oldPos.z != newPos.z) { //floor change extra cost lastStepCost = 2; } else if (Position::getDistanceX(newPos, oldPos) >= 1 && Position::getDistanceY(newPos, oldPos) >= 1) { //diagonal extra cost lastStepCost = 2; } } else { stopEventWalk(); } if (!summons.empty()) { //check if any of our summons is out of range (+/- 2 floors or 30 tiles away) std::list<Creature*> despawnList; std::list<Creature*>::iterator cit; for (cit = summons.begin(); cit != summons.end(); ++cit) { const Position pos = (*cit)->getPosition(); if (Position::getDistanceZ(newPos, pos) > 2 || (std::max<int32_t>(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30)) { despawnList.push_back((*cit)); } } for (cit = despawnList.begin(); cit != despawnList.end(); ++cit) { g_game.removeCreature((*cit), true); } } if (newTile->getZone() != oldTile->getZone()) { onChangeZone(getZone()); } //update map cache if (isMapLoaded) { if (teleport || oldPos.z != newPos.z) { updateMapCache(); } else { Tile* tile; const Position& myPos = getPosition(); Position pos; if (oldPos.y > newPos.y) { //north //shift y south for (int32_t y = mapWalkHeight - 1 - 1; y >= 0; --y) { memcpy(localMapCache[y + 1], localMapCache[y], sizeof(localMapCache[y])); } //update 0 for (int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x) { tile = g_game.getTile(myPos.getX() + x, myPos.getY() - ((mapWalkHeight - 1) / 2), myPos.z); updateTileCache(tile, x, -((mapWalkHeight - 1) / 2)); } } else if (oldPos.y < newPos.y) { // south //shift y north for (int32_t y = 0; y <= mapWalkHeight - 1 - 1; ++y) { memcpy(localMapCache[y], localMapCache[y + 1], sizeof(localMapCache[y])); } //update mapWalkHeight - 1 for (int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x) { tile = g_game.getTile(myPos.getX() + x, myPos.getY() + ((mapWalkHeight - 1) / 2), myPos.z); updateTileCache(tile, x, (mapWalkHeight - 1) / 2); } } if (oldPos.x < newPos.x) { // east //shift y west int32_t starty = 0; int32_t endy = mapWalkHeight - 1; int32_t dy = Position::getDistanceY(oldPos, newPos); if (dy < 0) { endy += dy; } else if (dy > 0) { starty = dy; } for (int32_t y = starty; y <= endy; ++y) { for (int32_t x = 0; x <= mapWalkWidth - 2; ++x) { localMapCache[y][x] = localMapCache[y][x + 1]; } } //update mapWalkWidth - 1 for (int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y) { tile = g_game.getTile(myPos.x + ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z); updateTileCache(tile, (mapWalkWidth - 1) / 2, y); } } else if (oldPos.x > newPos.x) { // west //shift y east int32_t starty = 0; int32_t endy = mapWalkHeight - 1; int32_t dy = Position::getDistanceY(oldPos, newPos); if (dy < 0) { endy += dy; } else if (dy > 0) { starty = dy; } for (int32_t y = starty; y <= endy; ++y) { for (int32_t x = mapWalkWidth - 2; x >= 0; --x) { localMapCache[y][x + 1] = localMapCache[y][x]; } } //update 0 for (int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y) { tile = g_game.getTile(myPos.x - ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z); updateTileCache(tile, -((mapWalkWidth - 1) / 2), y); } } updateTileCache(oldTile, oldPos); } } } else { if (isMapLoaded) { const Position& myPos = getPosition(); if (newPos.z == myPos.z) { updateTileCache(newTile, newPos); } if (oldPos.z == myPos.z) { updateTileCache(oldTile, oldPos); } } } if (creature == followCreature || (creature == this && followCreature)) { if (hasFollowPath) { isUpdatingPath = true; } if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) { onCreatureDisappear(followCreature, false); } } if (creature == attackedCreature || (creature == this && attackedCreature)) { if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) { onCreatureDisappear(attackedCreature, false); } else { if (hasExtraSwing()) { //our target is moving lets see if we can get in hit g_dispatcher.addTask(createTask(boost::bind(&Game::checkCreatureAttack, &g_game, getID()))); } if (newTile->getZone() != oldTile->getZone()) { onAttackedCreatureChangeZone(attackedCreature->getZone()); } } } }
void SimpleMissileSkill::execute( Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pOustersSkillSlot, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID, int HitBonus) throw(Error) { __BEGIN_TRY Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); // NPC는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pOusters, pTargetCreature ) || pTargetCreature->isNPC() ) { executeSkillFailException(pOusters, param.SkillType, param.Grade); return; } result.pTargetCreature = pTargetCreature; GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; if (param.ItemClass != Item::ITEM_CLASS_MAX) { Item* pItem = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != param.ItemClass || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, param.SkillType, param.Grade); return; } } SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pOusters, pTargetCreature, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. // Damage += computeMagicDamage(pTargetCreature, param.SkillDamage, param.SkillType, true); Damage += computeOustersMagicDamage(pOusters, pTargetCreature, param.SkillDamage, param.SkillType); } else { Damage += param.SkillDamage; } computeCriticalBonus(pOusters, param.SkillType, Damage, bCriticalHit); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pOusters, pTargetCreature, param.SkillType); bool bPK = verifyPK(pOusters, pTargetCreature); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot, HitBonus); } else { bHitRoll = HitRoll::isSuccess(pOusters, pTargetCreature); } ZoneCoord_t X = pOusters->getX(); ZoneCoord_t Y = pOusters->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK && bSatisfyRequire ) { decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pOusters); if (bCanSeeCaster) { setDamage(pTargetCreature, Damage, pOusters, param.SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pOusters, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pOusters, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); } else { setDamage(pTargetCreature, Damage, pOusters, param.SkillType, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pOusters, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); decreaseDurability(pOusters, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK6); } if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, 100, pOusters); shareOustersExp(pOusters, exp, _GCSkillToObjectOK1); } increaseAlignment(pOusters, pTargetCreature, _GCSkillToObjectOK1); _GCSkillToObjectOK1.setSkillType(param.SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK1.setGrade(param.Grade); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK2.setGrade(param.Grade); _GCSkillToObjectOK3.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK3.setGrade(param.Grade); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setGrade(param.Grade); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK5.setGrade(param.Grade); _GCSkillToObjectOK6.setXY(X, Y); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); _GCSkillToObjectOK6.setGrade(param.Grade); pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = NULL; if (pTargetCreature->isPC()) { pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pOusters); } list<Creature*> cList; cList.push_back(pOusters); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(X, Y, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(X, Y, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pOustersSkillSlot->setRunTime(param.Delay); result.bSuccess = true; } else { executeSkillFailNormal(pOusters, param.SkillType, pTargetCreature, param.Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, param.SkillType, param.Grade); } __END_CATCH }
inline bool ReactionFire::isPossible (Actor* shooter, const Edict* target) const { return isEnemy(shooter, target) && canReact(shooter, target) && canSee(shooter, target); }
bool Level::canSee(const Creature* c, Vec2 pos) const { return canSee(c->getPosition(), pos, c->getVision()); }
int tickAttackTower(gnode* grid,tower* t){ tower_type *type; if (t->type==BASE) return 0; type=typesTowerGet(t->type); if (type==0){ t->health=-1; return 0; } if (t->target==0){ //find near npc int x=idtox(t->position); int y=idtoy(t->position); int i,j,k; int yid,xid; npc* tmp; for (i=0;i<type->distanse;i++) for(j=0;j<config.area_size[i];j++) if (((xid=x+config.area_array[i][j].x)>=0 && x+config.area_array[i][j].x<config.gridsize) && ((yid=y+config.area_array[i][j].y)>=0 && y+config.area_array[i][j].y<config.gridsize)) for (k=0;k<MAX_GROUPS;k++) if (k!=config.players[t->owner].group) for(tmp=grid[to2d(xid,yid)].npcs[k]; tmp!=0;tmp=tmp->next) if (canSee(grid,&(vec){x+0.5,y+0.5},&tmp->position)>0) if(sqr(x+0.5-(tmp->position.x))+sqr(y+0.5-(tmp->position.y))<=sqr(type->distanse)){ t->target=tmp; setMask(t,TOWER_TARGET); if (rand()%100<60) return 0; } }else{ if (t->target->id==0) return 0; if(rand()%100<8){ t->target=0; return 0; } if (sqr(t->target->position.x-getGridx(t->position))+ sqr(t->target->position.y-getGridy(t->position))> sqr(type->distanse)){ t->target=0; return 0; } // printDebug("\t|%d %d\n",t->attack_count,type->attack_speed); if (t->attack_count>=type->attack_speed){ t->attack_count=0; bullet* b;//set params of bullet if ((b=newBullet())==0){ perror("newBullet tickAttackBullet"); return -1; } vec position={getGridx(t->position),getGridy(t->position)}; // getTargetPos(vec *pos, vec *dir, float v, vec * $pos, float $v){ // vec* target=getTargetPos(&t->target->position, // &t->target->direction, // config.npc_types[t->target->type].move_speed, // &position, // config.bullet_types[type->bullet_type].speed // ); memcpy(&b->position,&position,sizeof(vec)); memcpy(&b->source,&position,sizeof(vec)); //memcpy(&b->destination,target,sizeof(vec)); // printDebug("aaaa = %g|%g {%g|%g}\n",target->x,target->y,t->target->position.x,t->target->position.y); b->ntarget=t->target; b->destination.x=t->target->position.x; b->destination.y=t->target->position.y; b->max_dist=type->distanse; b->type=type->bullet_type; b->damage=type->damage; b->support=type->support; b->group=config.players[t->owner].group; b->owner=t->owner; setMask(b,BULLET_CREATE); // b->target=NPC; getDir(&b->position,&b->destination,&b->direction); // memcpy(&b->effects,&config.npc_types[n->type].effects,sizeof(effects)); } } /**/ return 0; }
void SimpleMissileSkill::execute( Monster* pMonster, Creature* pEnemy, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Assert(pMonster != NULL); Assert(pEnemy != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE)) { return; } if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pMonster, true); } result.pTargetCreature = pEnemy; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pMonster, pEnemy, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. Damage += computeMagicDamage(pEnemy, param.SkillDamage, param.SkillType); } else { Damage += param.SkillDamage; } bool bRangeCheck = verifyDistance(pMonster, pEnemy, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pMonster, pEnemy, param.SkillType); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pMonster, pSkillInfo); } else { bHitRoll = HitRoll::isSuccess(pMonster, pEnemy); } Coord_t vampX = pMonster->getX(); Coord_t vampY = pMonster->getY(); Coord_t targetX = pEnemy->getX(); Coord_t targetY = pEnemy->getY(); // 공격성공률 검증. if (bRangeCheck && bHitRoll && bCanHit) { bool bCanSeeCaster = canSee(pEnemy, pMonster); // 데미지를 가하고, 아이템 내구도를 떨어뜨린다. if (bCanSeeCaster) { setDamage(pEnemy, Damage, pMonster, param.SkillType, &_GCSkillToObjectOK2); decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK2); } else { setDamage(pEnemy, Damage, pMonster, param.SkillType, &_GCSkillToObjectOK6); decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK6); } _GCSkillToObjectOK2.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK2.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK3.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK5.setDuration(0); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); _GCSkillToObjectOK6.setXY(vampX, vampY); if (pEnemy->isPC()) { Player* pTargetPlayer = pEnemy->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pEnemy->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pEnemy); pTargetMonster->addEnemy(pMonster); } list<Creature*> cList; cList.push_back(pMonster); cList.push_back(pEnemy); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); result.bSuccess = true; } else { executeSkillFailNormal(pMonster, param.SkillType, pEnemy); } } catch (Throwable & t) { executeSkillFailException(pMonster, param.SkillType); } __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 SimpleMissileSkill::execute( Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID, int HitBonus) throw(Error) { __BEGIN_TRY Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, param.SkillType); return; } result.pTargetCreature = pTargetCreature; GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pVampire, pTargetCreature, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. Damage += computeMagicDamage(pTargetCreature, param.SkillDamage, param.SkillType, true, pVampire); } else { Damage += param.SkillDamage; } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pVampire, pTargetCreature, param.SkillType); bool bPK = verifyPK(pVampire, pTargetCreature); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); } else { bHitRoll = HitRoll::isSuccess(pVampire, pTargetCreature); } ZoneCoord_t vampX = pVampire->getX(); ZoneCoord_t vampY = pVampire->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); // 데미지를 가하고, 아이템 내구도를 떨어뜨린다. if (bCanSeeCaster) { setDamage(pTargetCreature, Damage, pVampire, param.SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); } else { setDamage(pTargetCreature, Damage, pVampire, param.SkillType, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK6); } // 상대가 죽었다면 경험치를 좀 올려준다. if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, KILL_EXP); shareVampExp(pVampire, exp, _GCSkillToObjectOK1); } increaseAlignment(pVampire, pTargetCreature, _GCSkillToObjectOK1); _GCSkillToObjectOK1.setSkillType(param.SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = NULL; if (pTargetCreature->isPC()) { pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pVampire); } list<Creature*> cList; cList.push_back(pVampire); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pVampireSkillSlot->setRunTime(param.Delay); result.bSuccess = true; } else { executeSkillFailNormal(pVampire, param.SkillType, pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, param.SkillType); } __END_CATCH }