void EffectReactiveArmor::unaffect(Creature* pCreature) throw(Error) { __BEGIN_TRY //cout << "EffectReactiveArmor" << "unaffect BEGIN" << endl; Assert(pCreature != NULL); Assert(pCreature->isOusters()); // 플래그를 끈다. pCreature->removeFlag(Effect::EFFECT_CLASS_REACTIVE_ARMOR); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pCreature); Assert(pTargetOusters != NULL); pTargetOusters->initAllStatAndSend(); // 이펙트를 삭제하라고 알려준다. GCRemoveEffect gcRemoveEffect; gcRemoveEffect.setObjectID(pCreature->getObjectID()); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_REACTIVE_ARMOR); pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcRemoveEffect); //cout << "EffectReactiveArmor" << "unaffect END" << endl; __END_CATCH }
void ActionStashOpen::execute (Creature * pCreature1 , Creature * pCreature2) throw(Error) { __BEGIN_TRY Assert(pCreature1 != NULL); Assert(pCreature2 != NULL); Assert(pCreature1->isNPC()); Assert(pCreature2->isPC()); // 만일 플레이어가 아직 이 존에서 보관함에 관련된 OID를 // 할당받지 않았다면 여기서 할당해 준다. if (pCreature2->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature2); if (!pSlayer->getStashStatus()) pSlayer->registerStash(); } else if (pCreature2->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature2); if (!pVampire->getStashStatus()) pVampire->registerStash(); } else if (pCreature2->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature2); if (!pOusters->getStashStatus()) pOusters->registerStash(); } GCNPCResponse okpkt; okpkt.setCode(NPC_RESPONSE_INTERFACE_STASHOPEN); pCreature2->getPlayer()->sendPacket(&okpkt); __END_CATCH }
void EffectComa::unaffect(Creature* pDeadCreature) throw(Error) { __BEGIN_TRY Assert(pDeadCreature != NULL); //Assert(pDeadCreature->isDead()); // 이펙트 플래그를 삭제해준다. pDeadCreature->removeFlag(Effect::EFFECT_CLASS_COMA); // 날아오면 강제로 죽이는 코드를 집어넣는다. if (pDeadCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pDeadCreature); pSlayer->setHP(0, ATTR_CURRENT); } else if (pDeadCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pDeadCreature); pVampire->setHP(0, ATTR_CURRENT); } else if (pDeadCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pDeadCreature); pOusters->setHP(0, ATTR_CURRENT); } __END_CATCH }
// Mysterious Item 가격 // itemClass와 pCreature의 능력치에 따라서 가격이 달라진다. Price_t PriceManager::getMysteriousPrice(Item::ItemClass itemClass, Creature* pCreature) const { int multiplier = 1; if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Attr_t CSTR = pSlayer->getSTR(ATTR_BASIC); Attr_t CDEX = pSlayer->getDEX(ATTR_BASIC); Attr_t CINT = pSlayer->getINT(ATTR_BASIC); Attr_t CSUM = CSTR + CDEX + CINT; // 0~20 사이 multiplier = CSUM / 15; } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Level_t CLevel = pVampire->getLevel(); // 0~20 사이 multiplier = CLevel / 5; } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); Level_t CLevel = pOusters->getLevel(); // 0~20 사이 multiplier = CLevel / 5; } // 1~20사이 multiplier = max(1, multiplier); // 가격 평균을 알아온다. InfoClassManager* pInfoClass = g_pItemInfoManager->getInfoManager(itemClass); Assert(pInfoClass!=NULL); // 가격 평균 * 능력치 비율? int finalPrice = (int)pInfoClass->getAveragePrice() * multiplier; // Blood Bible 보너스 적용 if (pCreature->isPC() ) { PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); int ratio = pPC->getGamblePriceRatio(); if (ratio != 0 ) { // ratio 값은 마이너스 값이다. finalPrice += getPercentValue(finalPrice, ratio); } } return finalPrice; }
bool EventQuestLootingInfo::isTargetMonster(PlayerCreature* pPC, Monster* pMonster ) const { if (pPC->getRace() == m_Race ) { QuestID_t qID; if (!pPC->getQuestManager()->hasEventQuest(m_QuestLevel, qID ) ) return false; QuestGrade_t qGrade; if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); qGrade = pSlayer->getQuestGrade(); } else if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); qGrade = pVampire->getLevel(); } else if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); qGrade = pOusters->getLevel(); } else { //cout << "³Í¹¹³Ä!" << endl; qGrade = 0; } if (qGrade < m_MinGrade || qGrade > m_MaxGrade ) return false; if (m_Type == LOOTING_ZONE || m_Type == LOOTING_BOTH ) { if (pMonster->getZoneID() != m_LootingZoneID ) return false; } if (m_Type == LOOTING_MONSTER || m_Type == LOOTING_BOTH ) { if (pMonster->getMonsterType() != m_LootingMonsterType ) return false; } return true; } else { return false; } }
GQuestElement::ResultType GQuestAdvanceClassElement::checkCondition(PlayerCreature* pPC ) const { if (pPC->getLevel() != 150 ) return FAIL; Exp_t advExp = 0; if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); SkillDomainType_t domain = pSlayer->getHighestSkillDomain(); DomainInfo* pDomainInfo = g_pSkillDomainInfoManager->getDomainInfo((SkillDomain)domain, pPC->getLevel()); if (pDomainInfo == NULL ) return FAIL; Exp_t goalExp = pDomainInfo->getGoalExp(); Exp_t currentExp = goalExp - pSlayer->getGoalExp(domain); advExp = (Exp_t)(currentExp * 0.0688933574); } else if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); VampEXPInfo* pExpInfo = g_pVampEXPInfoManager->getVampEXPInfo(pVampire->getLevel()); if (pExpInfo == NULL ) return FAIL; Exp_t goalExp = pExpInfo->getGoalExp(); Exp_t currentExp = goalExp - pVampire->getGoalExp(); advExp = currentExp / 100; } else if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); OustersEXPInfo* pExpInfo = g_pOustersEXPInfoManager->getOustersEXPInfo(pOusters->getLevel()); if (pExpInfo == NULL ) return FAIL; Exp_t goalExp = pExpInfo->getGoalExp(); Exp_t currentExp = goalExp - pOusters->getGoalExp(); advExp = currentExp / 100; } advExp = min((int)advExp, 18496191); // ÇϵåÄÚµù -_- pPC->increaseAdvancementClassExp(advExp, false); return OK; }
void DynamicZoneSlayerMirrorOfAbyss::killPC() { Assert(m_pZone != NULL); // PC 를 죽인다. map<ObjectID_t, Creature*>::const_iterator itr = m_pZone->getPCManager()->getCreatures().begin(); map<ObjectID_t, Creature*>::const_iterator endItr = m_pZone->getPCManager()->getCreatures().end(); for (; itr != endItr; ++itr ) { Assert(itr->second != NULL); if (itr->second->isPC() ) { PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(itr->second); Assert(pPC != NULL); if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); Assert(pSlayer != NULL); pSlayer->setHP(0); } else if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); Assert(pVampire != NULL); pVampire->setHP(0); } else if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); Assert(pOusters != NULL); pOusters->setHP(0); } } } }
//////////////////////////////////////////////////////////////////////////////// // 액션을 실행한다. //////////////////////////////////////////////////////////////////////////////// void ActionSetResurrectZone::execute (Creature * pCreature1 , Creature * pCreature2) throw(Error) { __BEGIN_TRY Assert(pCreature1 != NULL); Assert(pCreature2 != NULL); Assert(pCreature1->isNPC()); Assert(pCreature2->isPC()); // 일단 클라이언트를 위해서 OK 패킷을 함 날린다. GCNPCResponse okpkt; Player* pPlayer = pCreature2->getPlayer(); Assert(pPlayer != NULL); pPlayer->sendPacket(&okpkt); if (pCreature2->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature2); pSlayer->setResurrectZoneIDEx(m_ZoneID); } else if (pCreature2->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature2); pVampire->setResurrectZoneIDEx(m_ZoneID); } else if (pCreature2->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature2); pOusters->setResurrectZoneIDEx(m_ZoneID); } GCSystemMessage msg; msg.setMessage(g_pStringPool->getString(STRID_SET_RESURRECTION_POSITION )); pPlayer->sendPacket(&msg); __END_CATCH }
void EffectEvade::unaffect(Creature* pCreature) throw(Error) { __BEGIN_TRY //cout << "EffectEvade" << "unaffect BEGIN" << endl; Assert(pCreature != NULL); Assert(pCreature->isOusters()); // 플래그를 끈다. pCreature->removeFlag(Effect::EFFECT_CLASS_EVADE); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pCreature); Assert(pTargetOusters != NULL); OUSTERS_RECORD prev; pTargetOusters->getOustersRecord(prev); pTargetOusters->initAllStat(); pTargetOusters->sendRealWearingInfo(); pTargetOusters->sendModifyInfo(prev); // 이펙트를 삭제하라고 알려준다. GCRemoveEffect gcRemoveEffect; gcRemoveEffect.setObjectID(pCreature->getObjectID()); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_EVADE); pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcRemoveEffect); //cout << "EffectEvade" << "unaffect END" << endl; __END_CATCH }
void EffectDecreaseHP::unaffect(Creature* pCreature) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG Assert(pCreature != NULL); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); pCreature->removeFlag(Effect::EFFECT_CLASS_DECREASE_HP); Damage_t decreaseHP = m_Point; if (!(pZone->getZoneLevel() & COMPLETE_SAFE_ZONE) && !pCreature->isDead() && !pCreature->isFlag(Effect::EFFECT_CLASS_COMA) // 무적상태 체크. by sigi. 2002.9.5 && canAttack(NULL, pCreature ) ) { if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); HP_t CurrentHP = pSlayer->getHP(ATTR_CURRENT); if (CurrentHP > 0) { HP_t RemainHP = max(0, CurrentHP -(int)decreaseHP); pSlayer->setHP(RemainHP, ATTR_CURRENT); GCModifyInformation gcMI; gcMI.addShortData(MODIFY_CURRENT_HP, RemainHP); pSlayer->getPlayer()->sendPacket(&gcMI); // 변한 HP를 브로드캐스팅해준다. GCStatusCurrentHP pkt; pkt.setObjectID(pSlayer->getObjectID()); pkt.setCurrentHP(RemainHP); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &pkt); } } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); HP_t CurrentHP = pVampire->getHP(ATTR_CURRENT); if (CurrentHP > 0) { HP_t RemainHP = max(0, CurrentHP -(int)decreaseHP); pVampire->setHP(RemainHP, ATTR_CURRENT); GCModifyInformation gcMI; gcMI.addShortData(MODIFY_CURRENT_HP, RemainHP); pVampire->getPlayer()->sendPacket(&gcMI); // 공격(흡혈) 당하는 경우에는 공격자의 성향이 바뀜 by sigi. 2002.12.27 Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker!=NULL && pAttacker->isVampire()) { Vampire* pAttackVampire = dynamic_cast<Vampire*>(pAttacker); GCModifyInformation gcAttackerMI; computeAlignmentChange(pVampire, decreaseHP, pAttackVampire, NULL, &gcAttackerMI); // 뭔가 변한 정보가 있다면 보내준다. if (gcAttackerMI.getShortCount()+gcAttackerMI.getLongCount() > 0) { pAttackVampire->getPlayer()->sendPacket(&gcAttackerMI); } } // 변한 HP를 브로드캐스팅해준다. GCStatusCurrentHP pkt; pkt.setObjectID(pVampire->getObjectID()); pkt.setCurrentHP(RemainHP); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &pkt); } } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); HP_t CurrentHP = pOusters->getHP(ATTR_CURRENT); if (CurrentHP > 0) { HP_t RemainHP = max(0, CurrentHP -(int)decreaseHP); pOusters->setHP(RemainHP, ATTR_CURRENT); GCModifyInformation gcMI; gcMI.addShortData(MODIFY_CURRENT_HP, RemainHP); pOusters->getPlayer()->sendPacket(&gcMI); // 공격(흡혈) 당하는 경우에는 공격자의 성향이 바뀜 by sigi. 2002.12.27 Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker!=NULL && pAttacker->isOusters()) { Ousters* pAttackOusters = dynamic_cast<Ousters*>(pAttacker); GCModifyInformation gcAttackerMI; computeAlignmentChange(pOusters, decreaseHP, pAttackOusters, NULL, &gcAttackerMI); // 뭔가 변한 정보가 있다면 보내준다. if (gcAttackerMI.getShortCount()+gcAttackerMI.getLongCount() > 0) { pAttackOusters->getPlayer()->sendPacket(&gcAttackerMI); } } // 변한 HP를 브로드캐스팅해준다. GCStatusCurrentHP pkt; pkt.setObjectID(pOusters->getObjectID()); pkt.setCurrentHP(RemainHP); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &pkt); } } else if (pCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pCreature); HP_t CurrentHP = pMonster->getHP(ATTR_CURRENT); if (CurrentHP > 0) { HP_t RemainHP = max(0, CurrentHP -(int)decreaseHP); pMonster->setHP(RemainHP, ATTR_CURRENT); // 변한 HP를 브로드캐스팅해준다. GCStatusCurrentHP pkt; pkt.setObjectID(pMonster->getObjectID()); pkt.setCurrentHP(RemainHP); pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &pkt); if (RemainHP == 0 ) { Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker != NULL && pAttacker->isVampire() ) { Vampire* pAttackVampire = dynamic_cast<Vampire*>(pAttacker); GCModifyInformation gcMI; increaseAlignment(pAttackVampire, pCreature, gcMI); if (gcMI.getShortCount() > 0 || gcMI.getLongCount() > 0 ) pAttackVampire->getPlayer()->sendPacket(&gcMI); } } } } // m_CasterName이 pCreature를 죽인 경우의 KillCount 처리 // by sigi. 2002.9.9 if (pCreature->isDead()) { Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker!=NULL) { if (pAttacker->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pAttacker); // 죽일때 경험치를 준다. GCModifyInformation mi; int exp = computeCreatureExp(pCreature, KILL_EXP); shareVampExp(pVampire, exp, mi); if (pCreature->isMonster() ) { increaseFame(pVampire, decreaseHP); mi.addLongData(MODIFY_FAME, pVampire->getFame()); } pAttacker->getPlayer()->sendPacket(&mi); } else if (pAttacker->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pAttacker); GCModifyInformation mi; int exp = computeCreatureExp(pCreature, 100); shareOustersExp(pOusters, exp, mi); if (pCreature->isMonster() ) { increaseFame(pOusters, decreaseHP); mi.addLongData(MODIFY_FAME, pOusters->getFame()); } } affectKillCount(pAttacker, pCreature); } } } __END_DEBUG __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // // 일반 아이템을 처리한다. // ////////////////////////////////////////////////////////////////////////////// void CGShopRequestSellHandler::executeNormal (CGShopRequestSell* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ ObjectID_t NPCID = pPacket->getObjectID(); ObjectID_t ITEMOID = pPacket->getItemObjectID(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pCreature = pGamePlayer->getCreature(); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); BYTE index = 0; bool bSpecialItem = false; Zone* pZone = pPC->getZone(); if (pZone == NULL) return sendFailPacket(pPacket, pPlayer); Creature* pNPCBase = NULL; /* try { pNPCBase = pZone->getCreature(NPCID); } catch (NoSuchElementException & nsee) { pNPCBase = NULL; } */ // NoSuch제거. by sigi. 2002.5.2 pNPCBase = pZone->getCreature(NPCID); if (pNPCBase == NULL || !pNPCBase->isNPC()) return sendFailPacket(pPacket, pPlayer); NPC* pNPC = dynamic_cast<NPC*>(pNPCBase); // 플레이어가 팔려고 하는 아이템을 가지고 있는지 검사 Inventory* pInventory = pPC->getInventory(); //Gold_t playerMoney = pPC->getGold(); Item* pItem = pInventory->getItemWithObjectID(ITEMOID); ItemNum_t itemNumber = pItem->getNum(); Price_t itemPrice = g_pPriceManager->getPrice(pItem, pNPC->getMarketCondBuy(), SHOP_RACK_NORMAL, pPC) * itemNumber; // 플레이어의 인벤토리에 아이템을 제거한다. pInventory->deleteItem(ITEMOID); pItem->whenPCLost(pPC); if (!pItem->destroy()) { filelog("shopDBBug.txt", "NoSuchItemInDB-destroy: %s", pItem->toString().c_str()); throw DisconnectException("아이템 지울려는데 DB에 없다."); } // 만약 벨트라면 안에 있는 포션을 삭제해준다. // DB에서 지우는 것은 Belt::destroy()를 부르는 것만으로 포션까지 삭제된다. if (pItem->getItemClass() == Item::ITEM_CLASS_BELT) { Inventory* pBeltInventory = dynamic_cast<Belt*>(pItem)->getInventory(); for (int y=0; y<pBeltInventory->getHeight(); y++) { for (int x=0; x<pBeltInventory->getWidth(); x++) { Item* pBeltItem = pBeltInventory->getItem(x, y); if (pBeltItem != NULL) { pBeltInventory->deleteItem(x, y); SAFE_DELETE(pBeltItem); } } } } // Skull 일 경우 Variable Manager 에서 머리값 배수 값으로 가격을 새로 계산한다 if (pItem->getItemClass() == Item::ITEM_CLASS_SKULL) itemPrice = itemPrice * (g_pVariableManager->getHeadPriceBonus() / 100); // ItemTrace Log 를 남겨야 한다면 남긴다 if (pItem != NULL && pItem->isTraceItem() ) remainTraceLog(pItem, pCreature->getName() , pNPC->getName(), ITEM_LOG_DELETE, DETAIL_SHOPSELL); // 플레이어에게 물건값을 지불한다. // pPC->setGoldEx(playerMoney+itemPrice); // by sigi. 2002.9.4 pPC->increaseGoldEx(itemPrice); // 플레이어가 물건 팔 때 처리할 것들을 처리한다. pPC->sellItem(pItem); if (pItem->getItemClass() == Item::ITEM_CLASS_MOON_CARD && pItem->getItemType() == 4) addOlympicStat(pPC, 4, (uint)(itemNumber)); bool bClearDefaultOptionTypes = false; if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_ITEM && pItem->getItemType() >= 32 && pItem->getItemType() <= 36) bClearDefaultOptionTypes = true; // NPC에게 자리가 충분하다면 플레이어가 판 아이템을 보관한다. // 운영자 명령어로 만든 아이템은 바로 없앤다. // 단 스페셜 아이템만을 보관한다. 노말 아이템은 그냥 버림. // 퀘스트 아이템은 보관하지 않고 버린다. if (pNPC->getShopType()==SHOPTYPE_NORMAL && pItem->getCreateType()!=Item::CREATE_TYPE_CREATE && !pItem->getOptionTypeList().empty() && !pItem->isTimeLimitItem()) { bSpecialItem = true; index = pNPC->getFirstEmptySlot(SHOP_RACK_SPECIAL); if (index < SHOP_RACK_INDEX_MAX) { // 아이템을 추가한다. pNPC->insertShopItem(SHOP_RACK_SPECIAL, index, pItem); // 스페셜 아이템을 NPC가 진열장에 추가했으므로, 상점 버전이 올라간다. pNPC->increaseShopVersion(SHOP_RACK_SPECIAL); //////////////////////////////////////////////////////////////////////////// // 근처의 플레이어들에게는 GCShopBought를... //////////////////////////////////////////////////////////////////////////// int CenterX = pNPC->getX(); int CenterY = pNPC->getY(); Creature* pNearCreature = NULL; Player* pNearPlayer = NULL; GCShopBought boughtpkt; boughtpkt.setObjectID(NPCID); if (!pItem->getOptionTypeList().empty()) { boughtpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL)); boughtpkt.setShopType(SHOP_RACK_SPECIAL); } else { boughtpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL)); boughtpkt.setShopType(SHOP_RACK_NORMAL); } boughtpkt.setShopIndex(index); boughtpkt.setItemObjectID(ITEMOID); boughtpkt.setItemClass(pItem->getItemClass()); boughtpkt.setItemType(pItem->getItemType()); boughtpkt.setOptionType(pItem->getOptionTypeList()); boughtpkt.setDurability(pItem->getDurability()); boughtpkt.setSilver(pItem->getSilver()); boughtpkt.setGrade(pItem->getGrade()); boughtpkt.setEnchantLevel(pItem->getEnchantLevel()); //pZone->broadcastPacket(pNPC->getX(), pNPC->getY(), &boughtpkt, pPC); try { for (int zx=CenterX-5; zx<=CenterX+5; zx++) { for (int zy=CenterY-5; zy<=CenterY+5; zy++) { // 바운드를 넘어가지 않는가를 체크 if (!isValidZoneCoord(pZone, zx, zy)) continue; Tile & tile = pZone->getTile(zx, zy); // 걸어다니는 크리쳐를 검색 if (tile.hasCreature(Creature::MOVE_MODE_WALKING)) { pNearCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if (pNearCreature == NULL) continue; // 방금 물건을 판 플레이어라면 생략 if (pNearCreature->getObjectID() == pPC->getObjectID()) continue; // 만약 플레이어라면 패킷을 보내준다. if (pNearCreature->isPC()) { pNearPlayer = pNearCreature->getPlayer(); if (pNearPlayer == NULL) continue; pNearPlayer->sendPacket(&boughtpkt); } } // 날아다니는 크리쳐를 검색 if (tile.hasCreature(Creature::MOVE_MODE_FLYING)) { pNearCreature = tile.getCreature(Creature::MOVE_MODE_FLYING); if (pNearCreature == NULL) continue; // 방금 물건을 판 플레이어라면 생략 if (pNearCreature->getObjectID() == pPC->getObjectID()) continue; // 만약 플레이어라면 패킷을 보내준다. if (pNearCreature->isPC()) { pNearPlayer = pNearCreature->getPlayer(); if (pNearPlayer == NULL) continue; pNearPlayer->sendPacket(&boughtpkt); } } } // end of for (ZoneCoord_t zy=CenterY-5; zy<=CenterY+5; zy++) } // end of for (ZoneCoord_t zx=CenterX-5; zx<=CenterX+5; zx++) } catch (Throwable & t) { filelog("shopbug_packet.log", "%s", t.toString().c_str()); } } // if (index < SHOP_RACK_INDEX_MAX) else { SAFE_DELETE(pItem); } } // if (pItem->getOptionType() != 0) else { bSpecialItem = false; SAFE_DELETE(pItem); } // 물건을 산 플레이어에게 GCShopSellOK를...보낸다. GCShopSellOK okpkt; okpkt.setObjectID(NPCID); if (bSpecialItem) okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL)); else okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL)); okpkt.setItemObjectID(ITEMOID); //okpkt.setPrice(playerMoney+itemPrice); // playerMoney + itemPrice 가 MAX_MONEY를 넘어갈 수 있다. // 2003.1.8 by bezz okpkt.setPrice(pPC->getGold()); pPlayer->sendPacket(&okpkt); if (bClearDefaultOptionTypes ) { pPC->clearDefaultOptionTypes(); pPC->initAllStatAndSend(); if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); Assert(pSlayer != NULL); pSlayer->sendRealWearingInfo(); } else if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); Assert(pVampire != NULL); pVampire->sendRealWearingInfo(); } else if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); Assert(pOusters != NULL); pOusters->sendRealWearingInfo(); } } #endif __END_DEBUG_EX __END_CATCH }
void EffectAlignmentRecovery::affect(Creature* pCreature) throw(Error) { __BEGIN_TRY Assert(pCreature != NULL); Assert(pCreature->isPC()); Timeval CurrentTime; getCurrentTime(CurrentTime); GCModifyInformation gcModifyInformation; Alignment_t CurrentAlignment = 0; Alignment_t NewAlignment = 0; if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Assert(pSlayer != NULL); if (m_Period != 0) { // 플레그 걸귀 pSlayer->setFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); // 한 턴에 얼마나 회복 시킬 것인가. CurrentAlignment = pSlayer->getAlignment(); NewAlignment = min(10000, (int)(CurrentAlignment + m_AlignmentQuantity)); pSlayer->setAlignment(NewAlignment); gcModifyInformation.addLongData(MODIFY_ALIGNMENT, NewAlignment); pSlayer->getPlayer()->sendPacket(&gcModifyInformation); WORD AlignmentSaveCount = pSlayer->getAlignmentSaveCount(); if (AlignmentSaveCount > ALIGNMENT_SAVE_PERIOD) { StringStream msg; msg << "Alignment = " << NewAlignment; pSlayer->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pSlayer->setAlignmentSaveCount(AlignmentSaveCount); } else { // unaffect하면서 패킷이 날아갈 테니까.... setDeadline(0); } m_Period--; } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); if (m_Period != 0) { // 플레그 걸귀 pVampire->setFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); // 한 턴에 얼마나 회복 시킬 것인가. CurrentAlignment = pVampire->getAlignment(); NewAlignment = min(10000, CurrentAlignment + m_AlignmentQuantity); pVampire->setAlignment(NewAlignment); gcModifyInformation.addLongData(MODIFY_ALIGNMENT, NewAlignment); pVampire->getPlayer()->sendPacket(&gcModifyInformation); WORD AlignmentSaveCount = pVampire->getAlignmentSaveCount(); if (AlignmentSaveCount > ALIGNMENT_SAVE_PERIOD) { StringStream msg; msg << "Alignment = " << NewAlignment; pVampire->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pVampire->setAlignmentSaveCount(AlignmentSaveCount); } else { // unaffect하면서 패킷이 날아갈 테니까.... setDeadline(0); } m_Period--; } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); Assert(pOusters != NULL); if (m_Period != 0) { // 플레그 걸귀 pOusters->setFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); // 한 턴에 얼마나 회복 시킬 것인가. CurrentAlignment = pOusters->getAlignment(); NewAlignment = min(10000, CurrentAlignment + m_AlignmentQuantity); pOusters->setAlignment(NewAlignment); gcModifyInformation.addLongData(MODIFY_ALIGNMENT, NewAlignment); pOusters->getPlayer()->sendPacket(&gcModifyInformation); WORD AlignmentSaveCount = pOusters->getAlignmentSaveCount(); if (AlignmentSaveCount > ALIGNMENT_SAVE_PERIOD) { StringStream msg; msg << "Alignment = " << NewAlignment; pOusters->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pOusters->setAlignmentSaveCount(AlignmentSaveCount); } else { // unaffect하면서 패킷이 날아갈 테니까.... setDeadline(0); } m_Period--; } else { return; // 큰 의미는 없지만.. } // 성향 단계가 바뀌면 다른 사람들에게도 알려줘야 한다. by sigi. 2002.12.28 Alignment beforeAlignment = g_pAlignmentManager->getAlignmentType(CurrentAlignment); Alignment afterAlignment = g_pAlignmentManager->getAlignmentType(NewAlignment); if (beforeAlignment!=afterAlignment) { GCOtherModifyInfo gcOtherModifyInfo; gcOtherModifyInfo.setObjectID(pCreature->getObjectID()); gcOtherModifyInfo.addShortData(MODIFY_ALIGNMENT, NewAlignment); Zone* pZone = pCreature->getZone(); // 2003.1.10 Assert(pZone!=NULL); pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcOtherModifyInfo, pCreature); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Death::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); Assert(pSkillSlot != 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는 공격할 수 없다. // 저주 면역. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_CURSE) || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // Knowledge of Curse 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessVampireCurse(pSkillInfo->getLevel(), pTargetCreature->getResist(MAGIC_DOMAIN_CURSE)); bool bHitRoll2 = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pSkillSlot, HitBonus); bool bCanHit = canHit(pVampire, pTargetCreature, SkillType); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_DEATH); bool bPK = verifyPK(pVampire, pTargetCreature); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bCanHit && !bEffected && bPK) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // pTargetCreature가 저주마법을 반사하는 경우 if (CheckReflection(pVampire, pTargetCreature, getSkillType())) { pTargetCreature = (Creature*)pVampire; TargetObjectID = pVampire->getObjectID(); } Resist_t resist = pTargetCreature->getResist(MAGIC_DOMAIN_CURSE); if ((resist*10/3) > output.Duration ) output.Duration=0; else output.Duration -= resist*10/3; if (output.Duration < 20 ) output.Duration = 20; // 이펙트 오브젝트를 생성해 붙인다. EffectDeath* pEffect = new EffectDeath(pTargetCreature); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSkillInfo->getLevel()/2); pEffect->setResistPenalty(output.Damage); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DEATH); // 능력치를 계산해서 보내준다. if (pTargetCreature->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); if (bCanSeeCaster) { SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK2); } else { SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isVampire()) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); if (bCanSeeCaster) { pTargetVampire->addModifyInfo(prev, _GCSkillToObjectOK2); } else { pTargetVampire->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isOusters()) { Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); OUSTERS_RECORD prev; pTargetOusters->getOustersRecord(prev); pTargetOusters->initAllStat(); if (bCanSeeCaster) { pTargetOusters->addModifyInfo(prev, _GCSkillToObjectOK2); } else { pTargetOusters->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->initAllStat(); } else Assert(false); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(output.Duration); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); if (bCanSeeCaster) // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); } else // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3, cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4, cList); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer == NULL) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->addEnemy(pVampire); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_DEATH); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); //cout << pTargetCreature->getName() << "에게 Death를 " << output.Duration << " duration 동안 건다." << endl; pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void CGAddMouseToQuickSlotHandler::execute (CGAddMouseToQuickSlot* pPacket , Player* pPlayer) throw(ProtocolException, Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pCreature = pGamePlayer->getCreature(); bool Success = false; if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); InventorySlot* pExtraSlot = pSlayer->getExtraInventorySlot(); Item* pItem = pExtraSlot->getItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); Item::ItemClass IClass = pItem->getItemClass(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID != pPacket->getObjectID()) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 벨트를 입고 있지 않다면 벨트에다 아이템을 더할 수가 없다. if (!pSlayer->isWear(Slayer::WEAR_BELT)) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 포션도 아니고, 탄창도 아니라면 더할 수가 없지. if (IClass != Item::ITEM_CLASS_POTION && IClass != Item::ITEM_CLASS_MAGAZINE && IClass != Item::ITEM_CLASS_EVENT_ETC && IClass != Item::ITEM_CLASS_KEY) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } if (IClass == Item::ITEM_CLASS_EVENT_ETC && pItem->getItemType() < 14 ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Item* pBelt = pSlayer->getWearItem(Slayer::WEAR_BELT); Inventory* pBeltInventory = ((Belt*)pBelt)->getInventory(); if (pBeltInventory->canAdding(SlotID, 0, pItem)) { // 현재 벨트에 있는 Item을 받아온다. Item* pPrevItem = pBeltInventory->getItem(SlotID, 0); // 지정한 자리에 아이템이 있다면... if (pPrevItem != NULL) { // 아이템이 완전히 같은 아이템이라면... if (isStackable(pItem) && isSameItem(pItem, pPrevItem)) { int MaxStack = ItemMaxStack[pItem->getItemClass()]; if (pItem->getNum() + pPrevItem->getNum() > MaxStack) { ItemNum_t CurrentNum = pPrevItem->getNum(); ItemNum_t AddNum = pItem->getNum(); ItemNum_t NewNum = AddNum + CurrentNum - MaxStack; pPrevItem->setNum(MaxStack); pItem->setNum(NewNum); pBeltInventory->increaseNum(MaxStack - CurrentNum); pBeltInventory->increaseWeight(pItem->getWeight()* (MaxStack - CurrentNum)); //pPrevItem->save(pSlayer->getName(), STORAGE_BELT, pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", MaxStack, STORAGE_BELT, pBelt->getItemID(), SlotID); pPrevItem->tinysave(pField); //pItem->save(pSlayer->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d", NewNum, STORAGE_EXTRASLOT); pItem->tinysave(pField); Success = true; } else // 숫자가 9개를 넘지 않을 때. { pSlayer->deleteItemFromExtraInventorySlot(); pPrevItem->setNum(pPrevItem->getNum() + pItem->getNum()); pBeltInventory->increaseNum(pItem->getNum()); pBeltInventory->increaseWeight(pItem->getWeight()* pItem->getNum()); //pPrevItem->save(pSlayer->getName(), STORAGE_BELT , pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", pPrevItem->getNum(), STORAGE_BELT, pBelt->getItemID(), SlotID); pPrevItem->tinysave(pField); pItem->destroy(); SAFE_DELETE(pItem); Success = true; } } else // 클래스랑 타입이 같지 않을때 { // 마우스에 달려있는 아이템과 벨트에 있는 아이템을 제거한다. pSlayer->deleteItemFromExtraInventorySlot(); pBeltInventory->deleteItem(pPrevItem->getObjectID()); // 둘의 위치를 바꿔 준다. pSlayer->addItemToExtraInventorySlot(pPrevItem); pBeltInventory->addItem(SlotID , 0 , pItem); // DB에다가 저장을 한다. //pPrevItem->save(pSlayer->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pSlayer->getName(), STORAGE_BELT , pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pBelt->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } else // 슬랏에 아무런 기존의 아이템이 없을때. { // Inventory에 특정 아이템을 넣는다. pBeltInventory->addItem(SlotID, 0 , pItem); // 넣기에 성공하면 마우스에 달려있는 아이템을 없앤다. pSlayer->deleteItemFromExtraInventorySlot(); //pItem->save(pSlayer->getName(), STORAGE_BELT, pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pBelt->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } // end of if (pBeltInventory->canAdding(SlotID, 0, pItem)) } // if (pCreature->isSlayer()) else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); InventorySlot* pExtraSlot = pOusters->getExtraInventorySlot(); Item* pItem = pExtraSlot->getItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); Item::ItemClass IClass = pItem->getItemClass(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID != pPacket->getObjectID()) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Ousters::WearPart part = (SlotID > 2 ? Ousters::WEAR_ARMSBAND2 : Ousters::WEAR_ARMSBAND1); if (SlotID > 2 ) SlotID -= 3; // 해당 암스밴드가 없다 if (!pOusters->isWear(part)) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 푸파도 아니고, 콤포스메이도 아니라면 더할 수가 없지. if (IClass != Item::ITEM_CLASS_PUPA && IClass != Item::ITEM_CLASS_COMPOS_MEI && IClass != Item::ITEM_CLASS_EVENT_ETC ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } if (IClass == Item::ITEM_CLASS_EVENT_ETC && pItem->getItemType() < 14 ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Item* pArmsband = pOusters->getWearItem(part); Inventory* pArmsbandInventory = ((OustersArmsband*)pArmsband)->getInventory(); if (pArmsbandInventory->canAdding(SlotID, 0, pItem)) { // 현재 벨트에 있는 Item을 받아온다. Item* pPrevItem = pArmsbandInventory->getItem(SlotID, 0); // 지정한 자리에 아이템이 있다면... if (pPrevItem != NULL) { // 아이템이 완전히 같은 아이템이라면... if (isSameItem(pItem, pPrevItem)) { int MaxStack = ItemMaxStack[pItem->getItemClass()]; if (pItem->getNum() + pPrevItem->getNum() > MaxStack) { ItemNum_t CurrentNum = pPrevItem->getNum(); ItemNum_t AddNum = pItem->getNum(); ItemNum_t NewNum = AddNum + CurrentNum - MaxStack; pPrevItem->setNum(MaxStack); pItem->setNum(NewNum); pArmsbandInventory->increaseNum(MaxStack - CurrentNum); pArmsbandInventory->increaseWeight(pItem->getWeight()* (MaxStack - CurrentNum)); //pPrevItem->save(pOusters->getName(), STORAGE_BELT, pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", MaxStack, STORAGE_BELT, pArmsband->getItemID(), SlotID); pPrevItem->tinysave(pField); //pItem->save(pOusters->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d", NewNum, STORAGE_EXTRASLOT); pItem->tinysave(pField); Success = true; } else // 숫자가 9개를 넘지 않을 때. { pOusters->deleteItemFromExtraInventorySlot(); pPrevItem->setNum(pPrevItem->getNum() + pItem->getNum()); pArmsbandInventory->increaseNum(pItem->getNum()); pArmsbandInventory->increaseWeight(pItem->getWeight()* pItem->getNum()); //pPrevItem->save(pOusters->getName(), STORAGE_BELT , pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", pPrevItem->getNum(), STORAGE_BELT, pArmsband->getItemID(), SlotID); pPrevItem->tinysave(pField); pItem->destroy(); SAFE_DELETE(pItem); Success = true; } } else // 클래스랑 타입이 같지 않을때 { // 마우스에 달려있는 아이템과 벨트에 있는 아이템을 제거한다. pOusters->deleteItemFromExtraInventorySlot(); pArmsbandInventory->deleteItem(pPrevItem->getObjectID()); // 둘의 위치를 바꿔 준다. pOusters->addItemToExtraInventorySlot(pPrevItem); pArmsbandInventory->addItem(SlotID , 0 , pItem); // DB에다가 저장을 한다. //pPrevItem->save(pOusters->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pOusters->getName(), STORAGE_BELT , pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pArmsband->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } else // 슬랏에 아무런 기존의 아이템이 없을때. { // Inventory에 특정 아이템을 넣는다. pArmsbandInventory->addItem(SlotID, 0 , pItem); // 넣기에 성공하면 마우스에 달려있는 아이템을 없앤다. pOusters->deleteItemFromExtraInventorySlot(); //pItem->save(pOusters->getName(), STORAGE_BELT, pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pArmsband->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } // end of if (pArmsbandInventory->canAdding(SlotID, 0, pItem)) } // if (pCreature->isOusters()) // QuickSlot에 넣는 것을 실패 하였을때 실패 패킷을 날린다. if (!Success) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); } #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
void EffectAlignmentRecovery::unaffect(Creature* pCreature) throw(Error) { __BEGIN_TRY Assert(pCreature != NULL); if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Assert(pSlayer != NULL); Zone* pZone = pSlayer->getZone(); Assert(pZone != NULL); if (m_Period != 0) { // 한 턴에 얼마나 회복 시킬 것인가. Alignment_t CurrentAlignment = pSlayer->getAlignment(); Alignment_t NewAlignment = min(10000, (int)(CurrentAlignment + m_AlignmentQuantity* m_Period)); pSlayer->setAlignment(NewAlignment); WORD AlignmentSaveCount = pSlayer->getAlignmentSaveCount(); if (AlignmentSaveCount == 10) { StringStream msg; msg << "Alignment = " << NewAlignment; pSlayer->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pSlayer->setAlignmentSaveCount(AlignmentSaveCount); } // 현재 Alignment를 브로드캐스팅한다. // 이제 회복이 끝났나는 것을 알리도록 한다. // 자신에게 먼저 GCModifyInformation gcModifyInformation; gcModifyInformation.addLongData(MODIFY_ALIGNMENT, pSlayer->getAlignment()); pSlayer->getPlayer()->sendPacket(&gcModifyInformation); // 주변사람에게도 무언가를 날려줘야 한다. // 패킷을 새로 만들어야겠지.. pSlayer->removeFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); //Zone* pZone = pVampire->getZone(); if (m_Period != 0) { // 한 턴에 얼마나 회복 시킬 것인가. Alignment_t CurrentAlignment = pVampire->getAlignment(); Alignment_t NewAlignment = min(10000, (int)(CurrentAlignment + m_AlignmentQuantity* m_Period)); WORD AlignmentSaveCount = pVampire->getAlignmentSaveCount(); if (AlignmentSaveCount == 10) { StringStream msg; msg << "Alignment = " << NewAlignment; pVampire->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pVampire->setAlignmentSaveCount(AlignmentSaveCount); } // 현재 Alignment를 브로드캐스팅한다. // 이제 회복이 끝났나는 것을 알리도록 한다. // 자신에게 먼저 GCModifyInformation gcModifyInformation; gcModifyInformation.addLongData(MODIFY_ALIGNMENT, pVampire->getAlignment()); pVampire->getPlayer()->sendPacket(&gcModifyInformation); // 주변사람에게도.. pVampire->removeFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); //Zone* pZone = pOusters->getZone(); if (m_Period != 0) { // 한 턴에 얼마나 회복 시킬 것인가. Alignment_t CurrentAlignment = pOusters->getAlignment(); Alignment_t NewAlignment = min(10000, (int)(CurrentAlignment + m_AlignmentQuantity* m_Period)); WORD AlignmentSaveCount = pOusters->getAlignmentSaveCount(); if (AlignmentSaveCount == 10) { StringStream msg; msg << "Alignment = " << NewAlignment; pOusters->tinysave(msg.toString()); AlignmentSaveCount = 0; } else AlignmentSaveCount++; pOusters->setAlignmentSaveCount(AlignmentSaveCount); } // 현재 Alignment를 브로드캐스팅한다. // 이제 회복이 끝났나는 것을 알리도록 한다. // 자신에게 먼저 GCModifyInformation gcModifyInformation; gcModifyInformation.addLongData(MODIFY_ALIGNMENT, pOusters->getAlignment()); pOusters->getPlayer()->sendPacket(&gcModifyInformation); // 주변사람에게도.. pOusters->removeFlag(Effect::EFFECT_CLASS_ALIGNMENT_RECOVERY); } __END_CATCH }
void EffectPoison::affect(Creature* pCreature) throw(Error) { __BEGIN_TRY //cout << "EffectPoison " << "begin" << endl; Assert(pCreature != NULL); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); // 스킬 사용자를 가져온다. // !! 이미 존을 나갔을 수 있으므로 NULL이 될 수 있다. // by bezz. 2003.1.4 Creature* pCastCreature = pZone->getCreature(m_UserObjectID); // EffectPoison이 크리쳐에게 걸리게 되는 경우에는 현재로서는 // GreenPoison에 의해 타일 위에 생긴 // EffectGreenPoison 위를 플레이어가 지나갈 때 뿐이다. // EffectGreenPoison 내부에서 저항을 고려해서 데미지를 세팅한 다음 // EffectPoison을 붙이므로, 내부에서 한번 더 계산하면 안된다. //Damage_t PoisonDamage = computeMagicDamage(pCreature, m_Point, MAGIC_DOMAIN_POISON, m_Level); Damage_t PoisonDamage = m_Point; if (!(pZone->getZoneLevel() & COMPLETE_SAFE_ZONE) // 무적상태 체크. by sigi. 2002.9.5 && canAttack(pCastCreature, pCreature ) ) { if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); GCModifyInformation gcMI; ::setDamage(pSlayer, PoisonDamage, pCastCreature, SKILL_GREEN_POISON, &gcMI); pSlayer->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); GCModifyInformation gcMI; ::setDamage(pVampire, PoisonDamage, pCastCreature, SKILL_GREEN_POISON, &gcMI); pVampire->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); GCModifyInformation gcMI; ::setDamage(pOusters, PoisonDamage, pCastCreature, SKILL_GREEN_POISON, &gcMI); pOusters->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pCreature); ::setDamage(pMonster, PoisonDamage, pCastCreature, SKILL_GREEN_POISON); } // m_CasterName이 pCreature를 죽인 경우의 KillCount 처리 // by sigi. 2002.9.9 /* if (pCreature->isDead()) { Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker!=NULL) { affectKillCount(pAttacker, pCreature); } }*/ } setNextTime(m_Tick); //cout << "EffectPoison " << "end" << endl; __END_CATCH }
bool BloodDrain::executeMonster(Monster* pMonster, Creature* pEnemy) throw(Error) { __BEGIN_TRY bool isMaster = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif ; // 죽었으면 흡혈 못하고.. // 마스터는 아무나 다 빤다 - -; // 대상이 죽었으면 못 빤다. if (pMonster->isDead() || pMonster->isFlag(Effect::EFFECT_CLASS_COMA) || !pMonster->isEnemyToAttack(pEnemy) && !isMaster || pEnemy->isDead() || pEnemy->isFlag(Effect::EFFECT_CLASS_COMA)) { return false; } Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCBloodDrainOK1 _GCBloodDrainOK1; GCBloodDrainOK2 _GCBloodDrainOK2; GCBloodDrainOK3 _GCBloodDrainOK3; // 마스터는 체력 100% 라도 문다. int HPMultiplier = (isMaster? 1 : 3); // 현재 HP가 1/1, 1/3 bool bHitRoll = HitRoll::isSuccessBloodDrain(pMonster, pEnemy, HPMultiplier); bool bCanHit = canHit(pMonster, pEnemy, SKILL_BLOOD_DRAIN); // 마스터는 거리에 관계없이 문다~ bool bRangeCheck = isMaster || verifyDistance(pMonster, pEnemy, 1); // 흡혈 면역 상태. by sigi. 2002.9.13 bool bEffected = pEnemy->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN); if (bHitRoll && bCanHit && bRangeCheck && !bEffected) { if (pEnemy->isSlayer()) { // Set EffectBloodDrain // 마스터면 안건다. if (!isMaster) { EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy); pEffectBloodDrain->setLevel(pMonster->getLevel()); pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION); // 게임시간으로 3일 정도 pEnemy->addEffect(pEffectBloodDrain); pEffectBloodDrain->create(pEnemy->getName()); _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pEnemy); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->sendRealWearingInfo(); pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2); } // 로그를 남긴다. //log(LOG_BLOODDRAINED, pEnemy->getName(), "게임 내의 몬스터"); } // 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만.. // else if (pEnemy->isOusters() && !isMaster ) // { // EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy); // pEffectBloodDrain->setLevel(pMonster->getLevel()); // pEnemy->addEffect(pEffectBloodDrain); // pEffectBloodDrain->create(pEnemy->getName()); // _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // // pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // // Sight_t oldSight = pEnemy->getSight(); // Sight_t newSight = pEnemy->getEffectedSight(); // // if (oldSight != newSight ) // { // pEnemy->setSight(newSight); // pZone->updateScan(pEnemy, oldSight, pEnemy->getSight()); // _GCBloodDrainOK2.addShortData(MODIFY_VISION, pEnemy->getSight()); // // GCChangeDarkLight gcChangeDarkLight; // gcChangeDarkLight.setDarkLevel(15); // gcChangeDarkLight.setLightLevel(newSight); // pEnemy->getPlayer()->sendPacket(&gcChangeDarkLight); // } // } _GCBloodDrainOK3.setObjectID(pMonster->getObjectID()); _GCBloodDrainOK3.setTargetObjectID (pEnemy->getObjectID()); // 타겟이 뭐든 플래그는 건다. // 마스터면 안건다. if (!isMaster) { pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); } if (pEnemy != NULL && pEnemy->isPC()) { Player* pTargetPlayer = pEnemy->getPlayer(); if (pTargetPlayer != NULL) { _GCBloodDrainOK2.setObjectID(pMonster->getObjectID()); if (!isMaster) { // _GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION); } pTargetPlayer->sendPacket(&_GCBloodDrainOK2); } } // target int targetLevel = 0; int targetMaxHP = 0; if (pEnemy->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pEnemy); targetLevel = pTargetSlayer->getHighestSkillDomainLevel(); targetMaxHP = pTargetSlayer->getHP(ATTR_MAX); } else if (pEnemy->isVampire()) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pEnemy); targetLevel = pTargetVampire->getLevel(); targetMaxHP = pTargetVampire->getHP(ATTR_MAX); } else if (pEnemy->isOusters()) { Ousters* pTargetOusters = dynamic_cast<Ousters*>(pEnemy); targetLevel = pTargetOusters->getLevel(); targetMaxHP = pTargetOusters->getHP(ATTR_MAX); } else if (pEnemy->isMonster()) { Monster* pEnemyMonster = dynamic_cast<Monster*>(pEnemy); // 흡혈당하는 몬스터한테 딜레이 걸어준다. Timeval DelayTurn; DelayTurn.tv_sec = 4; DelayTurn.tv_usec = 500000; pEnemyMonster->addAccuDelay(DelayTurn); if ((pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif ) && pMonster->getClanType()==pEnemyMonster->getClanType()) { // 같은 clan의 마스터이면 피 상납이라고 볼 수 있을까 -_-; } else { pEnemyMonster->addEnemy(pMonster); } targetLevel = pEnemyMonster->getLevel(); targetMaxHP = pEnemyMonster->getHP(ATTR_MAX); } // 자신이나 상대방 중.. HP가 많은 쪽의 15~25% HP_t maxHP = max((int)pMonster->getHP(ATTR_MAX), targetMaxHP); HP_t drainHP = maxHP*(rand()%11+15)/100; // 15~25% // 한번에 1000이상 안 찬다. if (pMonster->getMonsterType() >= 717 ) drainHP = min((int)drainHP, 2000); else drainHP = min((int)drainHP, 1000); // 몬스터의 HP를 올려준다. HP_t CurrentHP = pMonster->getHP(); HP_t MaxHP = pMonster->getHP(ATTR_MAX); HP_t NewHP = min((int)MaxHP , (int)CurrentHP + (int)drainHP); // 뱀파이어의 HP를 세팅한다. pMonster->setHP(NewHP); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pMonster->getObjectID()); gcStatusCurrentHP.setCurrentHP(NewHP); pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &gcStatusCurrentHP); // 흡혈 당한 애의 HP를 줄인다. // 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage // by sigi. 2002.9.14 int drainDamage = 0; int myLevel = pMonster->getLevel(); if (targetLevel > myLevel) { drainDamage = targetMaxHP * (rand()%6+10) / 100; } else { // 레벨 5차이마다 1%씩 더~ int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel))); drainDamage = targetMaxHP * damagePercent / 100; } if (drainDamage > 0) { //decreaseHP(pZone, pEnemy, drainDamage); EffectDecreaseHP* pEffect = new EffectDecreaseHP(pEnemy); pEffect->setPoint(drainDamage); pEffect->setDeadline(20); // 2초 후 pEffect->setUserObjectID(pMonster->getObjectID()); pEnemy->addEffect(pEffect); pEnemy->setFlag(Effect::EFFECT_CLASS_DECREASE_HP); } // 흡혈 모습 보이게.. list<Creature *> cList; cList.push_back(pEnemy); cList.push_back(pMonster); pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &_GCBloodDrainOK3 , cList); // 흡혈 성공 return true; } __END_CATCH return false; }
void CGTradeMoneyHandler::executeOusters (CGTradeMoney* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // 상위 함수에서 검사를 했기 때문에, // 여기서는 포인터가 널인지를 검사하지 않는다. ObjectID_t TargetOID = pPacket->getTargetObjectID(); Gold_t Amount = pPacket->getAmount(); BYTE Code = pPacket->getCode(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pPC = pGamePlayer->getCreature(); Zone* pZone = pPC->getZone(); Creature* pTargetPC = pZone->getCreature(TargetOID); // NoSuch제거. by sigi. 2002.5.2 if (pTargetPC==NULL) return; Ousters* pSender = dynamic_cast<Ousters*>(pPC); Ousters* pReceiver = dynamic_cast<Ousters*>(pTargetPC); Player* pTargetPlayer = pTargetPC->getPlayer(); Gold_t finalAmount = Amount; Gold_t margin = 0; GCTradeMoney gcTradeMoney; GCTradeVerify gcTradeVerify; TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); // 교환 상태가 맞는지 체크를 해봐야한다. TradeInfo* pInfo1 = pTradeManager->getTradeInfo(pSender->getName()); TradeInfo* pInfo2 = pTradeManager->getTradeInfo(pReceiver->getName()); // 인벤토리에서 돈을 덜어, 교환창에다 더한다. if (Code == CG_TRADE_MONEY_INCREASE) { // 교환창에다 더할 액수보다 많은 돈을 가지고 있어야 한다. if (pSender->getGold() >= Amount) { // 돈을 받는 쪽이 맥스를 초과하게 된다면, 일부만 넣어줘야 한다. // 현재 교환 예정인 돈도 더해서 계산. by sigi. 2003.1.8 Gold_t receiverGold = pReceiver->getGold() + pInfo1->getGold(); if (receiverGold + Amount > MAX_MONEY) { margin = receiverGold + Amount - MAX_MONEY; finalAmount = finalAmount - margin; } // 인벤토리에서 돈을 빼고, 교환창에다 더한다. pSender->setGold(pSender->getGold() - finalAmount); pInfo1->setGold(pInfo1->getGold() + finalAmount); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { // 인증 패킷을 날려준다. gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_MONEY_INCREASE); pPlayer->sendPacket(&gcTradeVerify); } // 아이템을 더하거나 뺄 경우, 상태를 변환해줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 돈을 올린 당사자에게 실제로 인벤토리에서 // 빠진 금액이 얼마인지 보내준다. gcTradeMoney.setTargetObjectID(TargetOID); gcTradeMoney.setCode(GC_TRADE_MONEY_INCREASE_RESULT); gcTradeMoney.setAmount(finalAmount); pPlayer->sendPacket(&gcTradeMoney); // 상대방에게 바뀐 정보를 보내준다. gcTradeMoney.setTargetObjectID(pSender->getObjectID()); gcTradeMoney.setCode(GC_TRADE_MONEY_INCREASE); gcTradeMoney.setAmount(finalAmount); pTargetPlayer->sendPacket(&gcTradeMoney); } else { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_INCREASE_MONEY); return; } } // 교환창에서 돈을 덜어, 인벤토리에다가 더한다. else if (Code == CG_TRADE_MONEY_DECREASE) { // 인벤토리에다 더할 액수보다 교환창에 있는 돈이 많아야 한다. if (pInfo1->getGold() >= Amount) { // 돈이 맥스를 초과하게 된다면, 일부만 뺄 수 있다. Gold_t senderGold = pSender->getGold() + pInfo2->getGold(); if (senderGold + Amount > MAX_MONEY) { margin = senderGold + Amount - MAX_MONEY; finalAmount = finalAmount - margin; } // 인벤토리에다가 돈을 더하고, 교환창에서 돈을 뺀다. pSender->setGold(pSender->getGold() + finalAmount); pInfo1->setGold(pInfo1->getGold() - finalAmount); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { // 인증 패킷을 날려준다. gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_MONEY_DECREASE); pPlayer->sendPacket(&gcTradeVerify); } // 아이템을 더하거나 뺄 경우, 상태를 변환해줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 돈을 올린 당사자에게 실제로 인벤토리에다 // 더한 금액이 얼마인지 보내준다. gcTradeMoney.setTargetObjectID(TargetOID); gcTradeMoney.setCode(GC_TRADE_MONEY_DECREASE_RESULT); gcTradeMoney.setAmount(finalAmount); pPlayer->sendPacket(&gcTradeMoney); // 상대방에게 바뀐 정보를 보내준다. gcTradeMoney.setTargetObjectID(pSender->getObjectID()); gcTradeMoney.setCode(GC_TRADE_MONEY_DECREASE); gcTradeMoney.setAmount(finalAmount); pTargetPlayer->sendPacket(&gcTradeMoney); } else { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_DECREASE_MONEY); return; } } #endif __END_DEBUG_EX __END_CATCH }
//////////////////////////////////////////////////////////////////////////////// // 액션을 실행한다. //////////////////////////////////////////////////////////////////////////////// void ActionActivatePortal::execute (Creature * pNPC , Creature * pCreature) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG Assert(pCreature != NULL); Assert(pCreature->isPC()); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pCreature->getPlayer()); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); //Zone* pZone = pCreature->getZone(); bool bTransport = true; #if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) try { ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(m_ZoneID); // 유료존인데 유료사용자가 아니면... if (pZoneInfo==NULL || pZoneInfo->isPayPlay() && !pGamePlayer->isPayPlaying()) { string connectIP = pGamePlayer->getSocket()->getHost(); // 유료 서비스 사용이 가능한가? if (pGamePlayer->loginPayPlay(connectIP, pGamePlayer->getID())) { sendPayInfo(pGamePlayer); } else if (!pGamePlayer->isFamilyFreePass() ) // 패밀리 프리 패스는 유료존으로 갈 수 있다. { // 유료 서비스 사용 불가인 경우 GCSystemMessage gcSystemMessage; if (g_pConfig->getPropertyInt("IsNetMarble")==0) { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER_PAY_ZONE)); } else { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); } pGamePlayer->sendPacket (&gcSystemMessage); bTransport = false; } } } catch (NoSuchElementException&) { } #endif if (bTransport) { if (m_ZoneID == 1410 ) { if (pCreature->isFlag(Effect::EFFECT_CLASS_CAN_ENTER_GDR_LAIR ) ) { Effect* pEffect = pCreature->findEffect(Effect::EFFECT_CLASS_CAN_ENTER_GDR_LAIR); if (pEffect != NULL ) pEffect->setDeadline(0); } if (pCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Assert(pSlayer != NULL); // 오토바이를 타고 있으면 오토바이에서 내린다. if (pSlayer->hasRideMotorcycle() ) { pSlayer->getOffMotorcycle(); } } if (pCreature->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); Assert(pOusters != NULL); // 실프 타고 있으면 내려준다 if (pOusters->isFlag(Effect::EFFECT_CLASS_SUMMON_SYLPH) ) { Effect* pEffect = pOusters->findEffect(Effect::EFFECT_CLASS_SUMMON_SYLPH); if (pEffect != NULL ) pEffect->setDeadline(0); } } if (pCreature->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); if (pVampire->isFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_BAT) ) { addUntransformCreature(pVampire->getZone(), pVampire, true); } } } if (pNPC != NULL ) { pPC->getGQuestManager()->illegalWarp(); } transportCreature(pCreature, m_ZoneID, m_X, m_Y, true); } else { GCNPCResponse response; response.setCode(NPC_RESPONSE_QUIT_DIALOGUE); pGamePlayer->sendPacket(&response); } __END_DEBUG __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Liberty::execute(Ousters* pOusters, ObjectID_t TargetObjectID, 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; } Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isOusters()) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()) && canHit(pOusters, pTargetCreature, SkillType, pOustersSkillSlot->getExpLevel()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bHPCheck = pTargetOusters->isFlag(Effect::EFFECT_CLASS_PARALYZE); int Ratio = 0; EffectParalyze* pEffect = dynamic_cast<EffectParalyze*>(pTargetOusters->findEffect(Effect::EFFECT_CLASS_PARALYZE )); if (pEffect != NULL ) { if (pOustersSkillSlot->getExpLevel() <= 15 ) { Ratio = (int)((pOusters->getLevel() + (pOustersSkillSlot->getExpLevel() * 8.0 / 3.0 ) ) - pEffect->getLevel()); } else { Ratio = (int)((pOusters->getLevel() + 20 + (pOustersSkillSlot->getExpLevel() * 4.0 / 3.0 ) ) - pEffect->getLevel()); if (pOustersSkillSlot->getExpLevel() == 30 ) Ratio = (int)(Ratio * 1.1); } } bool bHitRoll2 = (rand()%100) < Ratio; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bSatisfyRequire && bHPCheck) { // 마나를 줄인다. decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); // 이펙트의 효과와 지속시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; input.TargetType = SkillInput::TARGET_OTHER; computeOutput(input, output); pEffect->setDeadline(0); // 패킷을 준비해서 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pOusters != pTargetCreature && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } list<Creature*> cList; cList.push_back(pOusters); cList.push_back(pTargetCreature); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &_GCSkillToObjectOK5 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void CGAddMouseToGearHandler::execute (CGAddMouseToGear* pPacket , Player* pPlayer) throw(ProtocolException, Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); try { GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); bool Success = false; if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Assert(pSlayer != NULL); Item* pItem = pSlayer->getExtraInventorySlotItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID == pPacket->getObjectID()) { Item::ItemClass IClass = pItem->getItemClass(); switch (SlotID) // 슬랏을 보고 그 슬랏에 맞는 아이템 유형인지 비교한다. { case Slayer::WEAR_HEAD: if (IClass == Item::ITEM_CLASS_HELM) Success = true; break; case Slayer::WEAR_NECK: if (IClass == Item::ITEM_CLASS_NECKLACE) Success = true; break; case Slayer::WEAR_FINGER1: if (IClass == Item::ITEM_CLASS_RING || IClass == Item::ITEM_CLASS_COUPLE_RING) Success = true; break; case Slayer::WEAR_FINGER2: if (IClass == Item::ITEM_CLASS_RING || IClass == Item::ITEM_CLASS_COUPLE_RING) Success = true; break; case Slayer::WEAR_FINGER3: if (IClass == Item::ITEM_CLASS_RING || IClass == Item::ITEM_CLASS_COUPLE_RING) Success = true; break; case Slayer::WEAR_FINGER4: if (IClass == Item::ITEM_CLASS_RING || IClass == Item::ITEM_CLASS_COUPLE_RING) Success = true; break; case Slayer::WEAR_WRIST1: if (IClass == Item::ITEM_CLASS_BRACELET) Success = true; break; case Slayer::WEAR_WRIST2: if (IClass == Item::ITEM_CLASS_BRACELET) Success = true; break; case Slayer::WEAR_LEFTHAND: if (IClass == Item::ITEM_CLASS_SHIELD) Success = true; break; case Slayer::WEAR_HAND3: if (IClass == Item::ITEM_CLASS_GLOVE) Success = true; break; case Slayer::WEAR_BODY: if (IClass == Item::ITEM_CLASS_COAT) Success = true; break; case Slayer::WEAR_BELT: if (IClass == Item::ITEM_CLASS_BELT) Success = true; break; case Slayer::WEAR_LEG: if (IClass == Item::ITEM_CLASS_TROUSER) Success = true; break; case Slayer::WEAR_FOOT: if (IClass == Item::ITEM_CLASS_SHOES) Success = true; break; case Slayer::WEAR_RIGHTHAND: if (isSlayerWeapon(IClass)) Success = true; break; case Slayer::WEAR_ZAP1: case Slayer::WEAR_ZAP2: case Slayer::WEAR_ZAP3: case Slayer::WEAR_ZAP4: if (IClass == Item::ITEM_CLASS_CORE_ZAP) Success = true; break; case Slayer::WEAR_PDA: if (IClass == Item::ITEM_CLASS_CARRYING_RECEIVER) Success = true; break; case Slayer::WEAR_SHOULDER: if (IClass == Item::ITEM_CLASS_SHOULDER_ARMOR) Success = true; break; default : break; } // 그 슬랏에 맞는 아이템을 장착하려고 하는지 체크한다. if (Success) pSlayer->wearItem((Slayer::WearPart)SlotID); } } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); Item* pItem = pVampire->getExtraInventorySlotItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID == pPacket->getObjectID()) { Item::ItemClass IClass = pItem->getItemClass(); switch (SlotID) // 슬랏을 보고 그 슬랏에 맞는 아이템 유형인지 비교한다. { case Vampire::WEAR_NECK: if (IClass == Item::ITEM_CLASS_VAMPIRE_NECKLACE) Success = true; break; case Vampire::WEAR_FINGER1: if (IClass == Item::ITEM_CLASS_VAMPIRE_RING || IClass == Item::ITEM_CLASS_VAMPIRE_COUPLE_RING) Success = true; break; case Vampire::WEAR_FINGER2: if (IClass == Item::ITEM_CLASS_VAMPIRE_RING || IClass == Item::ITEM_CLASS_VAMPIRE_COUPLE_RING) Success = true; break; case Vampire::WEAR_FINGER3: if (IClass == Item::ITEM_CLASS_VAMPIRE_RING || IClass == Item::ITEM_CLASS_VAMPIRE_COUPLE_RING) Success = true; break; case Vampire::WEAR_FINGER4: if (IClass == Item::ITEM_CLASS_VAMPIRE_RING || IClass == Item::ITEM_CLASS_VAMPIRE_COUPLE_RING) Success = true; break; case Vampire::WEAR_WRIST1: if (IClass == Item::ITEM_CLASS_VAMPIRE_BRACELET) Success = true; break; case Vampire::WEAR_WRIST2: if (IClass == Item::ITEM_CLASS_VAMPIRE_BRACELET) Success = true; break; case Vampire::WEAR_EARRING1: if (IClass == Item::ITEM_CLASS_VAMPIRE_EARRING) Success = true; break; case Vampire::WEAR_EARRING2: if (IClass == Item::ITEM_CLASS_VAMPIRE_EARRING) Success = true; break; case Vampire::WEAR_BODY: if (IClass == Item::ITEM_CLASS_VAMPIRE_COAT) Success = true; break; case Vampire::WEAR_LEFTHAND: if (IClass == Item::ITEM_CLASS_VAMPIRE_WEAPON) Success = true; break; case Vampire::WEAR_RIGHTHAND: if (IClass == Item::ITEM_CLASS_VAMPIRE_WEAPON) Success = true; break; case Vampire::WEAR_AMULET1: if (IClass == Item::ITEM_CLASS_VAMPIRE_AMULET) Success = true; break; case Vampire::WEAR_AMULET2: if (IClass == Item::ITEM_CLASS_VAMPIRE_AMULET) Success = true; break; case Vampire::WEAR_AMULET3: if (IClass == Item::ITEM_CLASS_VAMPIRE_AMULET) Success = true; break; case Vampire::WEAR_AMULET4: if (IClass == Item::ITEM_CLASS_VAMPIRE_AMULET) Success = true; break; case Vampire::WEAR_ZAP1: case Vampire::WEAR_ZAP2: case Vampire::WEAR_ZAP3: case Vampire::WEAR_ZAP4: if (IClass == Item::ITEM_CLASS_CORE_ZAP) Success = true; break; case Vampire::WEAR_DERMIS: if (IClass == Item::ITEM_CLASS_DERMIS) Success = true; break; case Vampire::WEAR_PERSONA: if (IClass == Item::ITEM_CLASS_PERSONA) Success = true; break; default : break; } // 그 슬랏에 맞는 아이템을 장착하려고 하는지 체크한다. if (Success) pVampire->wearItem((Vampire::WearPart)SlotID); } } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); Assert(pOusters != NULL); Item* pItem = pOusters->getExtraInventorySlotItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID == pPacket->getObjectID()) { Item::ItemClass IClass = pItem->getItemClass(); switch (SlotID) // 슬랏을 보고 그 슬랏에 맞는 아이템 유형인지 비교한다. { case Ousters::WEAR_CIRCLET: if (IClass == Item::ITEM_CLASS_OUSTERS_CIRCLET) Success = true; break; case Ousters::WEAR_COAT: if (IClass == Item::ITEM_CLASS_OUSTERS_COAT) Success = true; break; case Ousters::WEAR_LEFTHAND: case Ousters::WEAR_RIGHTHAND: if (IClass == Item::ITEM_CLASS_OUSTERS_WRISTLET || IClass == Item::ITEM_CLASS_OUSTERS_CHAKRAM ) Success = true; break; case Ousters::WEAR_BOOTS: if (IClass == Item::ITEM_CLASS_OUSTERS_BOOTS) Success = true; break; case Ousters::WEAR_ARMSBAND1: case Ousters::WEAR_ARMSBAND2: if (IClass == Item::ITEM_CLASS_OUSTERS_ARMSBAND) Success = true; break; case Ousters::WEAR_RING1: case Ousters::WEAR_RING2: if (IClass == Item::ITEM_CLASS_OUSTERS_RING) Success = true; break; case Ousters::WEAR_NECKLACE1: case Ousters::WEAR_NECKLACE2: case Ousters::WEAR_NECKLACE3: if (IClass == Item::ITEM_CLASS_OUSTERS_PENDENT) Success = true; break; case Ousters::WEAR_STONE1: case Ousters::WEAR_STONE2: case Ousters::WEAR_STONE3: case Ousters::WEAR_STONE4: if (IClass == Item::ITEM_CLASS_OUSTERS_STONE) Success = true; break; case Ousters::WEAR_ZAP1: case Ousters::WEAR_ZAP2: case Ousters::WEAR_ZAP3: case Ousters::WEAR_ZAP4: if (IClass == Item::ITEM_CLASS_CORE_ZAP) Success = true; break; case Ousters::WEAR_FASCIA: if (IClass == Item::ITEM_CLASS_FASCIA) Success = true; break; case Ousters::WEAR_MITTEN: if (IClass == Item::ITEM_CLASS_MITTEN) Success = true; break; default : break; } // 그 슬랏에 맞는 아이템을 장착하려고 하는지 체크한다. if (Success) pOusters->wearItem((Ousters::WearPart)SlotID); } } // Adding에 실패 하였을 경우 if (!Success) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); } } catch (Throwable & t) { //cout << t.toString(); } #endif // __GAME_SERVER__ __END_DEBUG_EX __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 }
////////////////////////////////////////////////////////////////////////////// // 클라이언트가 CGLogout 패킷을 보내면, 게임 서버는 크리처를 존에서 삭제하고, // 크리처와 아이템 정보를 DB에 저장한 후, 접속을 종료한다. ////////////////////////////////////////////////////////////////////////////// void CGLogoutHandler::execute (CGLogout* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // Assert(pPacket != NULL); Assert(pPlayer != NULL); // 새로그인 구조에서는 Logout을 하면 대기 상태로 나가야 한다. // Logout 패킷을 받으면 플레이어를 IncomingPlayerManager로 보낸다. GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); //cout << "CGLogoutHandler: " << pGamePlayer->getID() << endl; Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); // 나는 나간다 라고 로그를 남긴다. pGamePlayer->logLoginoutDateTime(); try { // 로그아웃할때 성물, 피의 성서 조각을 떨어뜨린다. // bool bSendPacket = false; // dropRelicToZone(pCreature, bSendPacket); if (pCreature->isPLAYER() && g_pPKZoneInfoManager->isPKZone(pCreature->getZoneID() ) ) { g_pPKZoneInfoManager->leavePKZone(pCreature->getZoneID()); } if (g_pConfig->hasKey("Hardcore") && g_pConfig->getPropertyInt("Hardcore")!=0 && pPacket==NULL ) { } else { // 크리처의 정보를 저장한다. pCreature->save(); if (pCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); pSlayer->tinysave("LastPlayDate=now()"); } else if (pCreature->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); pVampire->tinysave("LastPlayDate=now()"); } else if (pCreature->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); pOusters->tinysave("LastPlayDate=now()"); } ////////////////////////////////////////////////////////////// // 플레이어가 COMA상태(현재 죽은 상태)라면 로그아웃시 자동으로 // 부활위치로 캐릭터를 이동시킨다. // Login/Logout의 반복으로 부활기술을 사용하지 못하게 함 // // Creature의 정보를 먼저 DB에 업데이트한 후 새로 업데이트를 한다. ////////////////////////////////////////////////////////////// // 이터니티를 한번 쓴 상태로 로그아웃하면 부활 위치로 날라간다. if (pCreature->isFlag(Effect::EFFECT_CLASS_COMA) || pCreature->isFlag(Effect::EFFECT_CLASS_ETERNITY)) { //cout << "COMA 상태에서 로그아웃했음" << endl; ZoneID_t ZoneID = 0; ZoneCoord_t ZoneX = 0; ZoneCoord_t ZoneY = 0; ZONE_COORD ResurrectCoord; if (pCreature->isPC() ) { PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); g_pResurrectLocationManager->getPosition(pPC, ResurrectCoord); ZoneID = ResurrectCoord.id; ZoneX = ResurrectCoord.x; ZoneY = ResurrectCoord.y; char pField[80]; sprintf(pField, "ZoneID=%d, XCoord=%d, YCoord=%d, CurrentHP=HP", ZoneID, ZoneX, ZoneY); if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); pSlayer->tinysave(pField); } else if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); pVampire->tinysave(pField); } else if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); pOusters->tinysave(pField); } } } // 포스 스크롤이 켜져 있으면 로그아웃하면저 저장한다. if (pCreature->isFlag(Effect::EFFECT_CLASS_BEHEMOTH_FORCE_SCROLL) ) { Effect* pEffect = pCreature->findEffect(Effect::EFFECT_CLASS_BEHEMOTH_FORCE_SCROLL); pEffect->save(pCreature->getName()); } if (pCreature->isFlag(Effect::EFFECT_CLASS_SAFE_FORCE_SCROLL) ) { Effect* pEffect = pCreature->findEffect(Effect::EFFECT_CLASS_SAFE_FORCE_SCROLL); pEffect->save(pCreature->getName()); } if (pCreature->isFlag(Effect::EFFECT_CLASS_CARNELIAN_FORCE_SCROLL) ) { Effect* pEffect = pCreature->findEffect(Effect::EFFECT_CLASS_CARNELIAN_FORCE_SCROLL); pEffect->save(pCreature->getName()); } /* if(pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); Assert(pSlayer != NULL); if (g_pResurrectLocationManager->getSlayerPosition(pSlayer->getResurrectZoneID(), ResurrectCoord)) { ZoneID = ResurrectCoord.id; ZoneX = ResurrectCoord.x; ZoneY = ResurrectCoord.y; } else { if (g_pResurrectLocationManager->getSlayerPosition(pSlayer->getZone()->getZoneID(), ResurrectCoord)) { ZoneID = ResurrectCoord.id; ZoneX = ResurrectCoord.x; ZoneY = ResurrectCoord.y; } else { throw Error("Critical Error: ResurrectInfo is not established"); } } char pField[80]; sprintf(pField, "ZoneID=%d, XCoord=%d, YCoord=%d, CurrentHP=HP", ZoneID, ZoneX, ZoneY); pSlayer->tinysave(pField); } else if(pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); if (g_pResurrectLocationManager->getVampirePosition(pVampire->getResurrectZoneID(), ResurrectCoord)) { ZoneID = ResurrectCoord.id; ZoneX = ResurrectCoord.x; ZoneY = ResurrectCoord.y; } else { if (g_pResurrectLocationManager->getVampirePosition(pVampire->getZone()->getZoneID(), ResurrectCoord)) { ZoneID = ResurrectCoord.id; ZoneX = ResurrectCoord.x; ZoneY = ResurrectCoord.y; } else { throw Error("Critical Error: ResurrectInfo is not established"); } } // 이제 정보를 저장한다. char pField[80]; sprintf(pField, "ZoneID=%d, XCoord=%d, YCoord=%d, CurrentHP=HP", ZoneID, ZoneX, ZoneY); pVampire->tinysave(pField); } */ } // // 이제, 존에서 PC를 삭제한다. // // *CAUTION* // // pCreature의 좌표가 실제로 pCreature가 존재하는 타일의 좌표와 같아야 한다. // 따라서, 이 메쏘드를 호출하기 전에 좌표를 잘 바꿔놔야 한당.. // pZone->deleteCreature(pCreature , pCreature->getX() , pCreature->getY()); ////cout << "PC deleted from Zone >> "; // 존그룹의 ZPM에서 플레이어를 삭제한다. // ZonePlayerManager의 ProcessCommand 안에서 지우는 것이므로 반드시 NoBlocked 으로 지워야 한다. pZone->getZoneGroup()->getZonePlayerManager()->deletePlayer(pGamePlayer->getSocket()->getSOCKET()); // IPM으로 플레이어를 옮긴다. //g_pIncomingPlayerManager->pushPlayer(pGamePlayer); // Core의 구조를 바꾸면서 쓰레드로 부터 독립적으로 행하기 위하여 뒤에 한꺼번에 처리하기 위해서 // OutList로 넣는다. pZone->getZoneGroup()->getZonePlayerManager()->pushOutPlayer(pGamePlayer); ////cout << "Move PC to IPM >> "; } catch (NoSuchElementException & nsee) { throw DisconnectException(); } // 로그인 서버로 GLIncomingConnection을 보낸다. // PlayerName과 ClientIP를 같이 실어서 보낸다. /* GLIncomingConnection glIncomingConnection; glIncomingConnection.setPlayerID(pGamePlayer->getID()); glIncomingConnection.setClientIP(pGamePlayer->getSocket()->getHost()); if (g_pConfig->getProperty("User") == "excel96") g_pLoginServerManager->sendPacket("211.117.52.12" , g_pConfig->getPropertyInt("LoginServerUDPPort"), &glIncomingConnection); else if (g_pConfig->getProperty("User") == "elcastle") g_pLoginServerManager->sendPacket("211.117.52.12" , g_pConfig->getPropertyInt("LoginServerUDPPort"), &glIncomingConnection); else if (g_pConfig->getProperty("User") == "elca") g_pLoginServerManager->sendPacket("211.117.52.12" , g_pConfig->getPropertyInt("LoginServerUDPPort"), &glIncomingConnection); */ pGamePlayer->setPlayerStatus(GPS_AFTER_SENDING_GL_INCOMING_CONNECTION); #endif __END_DEBUG_EX __END_CATCH }
void CGSkillToInventoryHandler::execute (CGSkillToInventory* pPacket , Player* pPlayer) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); // by sigi if (pGamePlayer->getPlayerStatus() == GPS_NORMAL) { Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); // by sigi Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); SkillType_t SkillType = pPacket->getSkillType(); // 완전 안전지대라면 기술 사용 불가. by sigi. 2002.11.14 ZoneLevel_t ZoneLevel = pZone->getZoneLevel(pCreature->getX(), pCreature->getY()); if ((ZoneLevel & COMPLETE_SAFE_ZONE) || (pCreature->isFlag(Effect::EFFECT_CLASS_PARALYZE)) || (pCreature->isFlag(Effect::EFFECT_CLASS_CAUSE_CRITICAL_WOUNDS)) || (pCreature->isFlag(Effect::EFFECT_CLASS_EXPLOSION_WATER)) || (pCreature->isFlag(Effect::EFFECT_CLASS_COMA))) { GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(SkillType); pPlayer->sendPacket(&_GCSkillFailed1); return; } if (pCreature->isFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_WERWOLF)) { switch(SkillType) { case SKILL_ATTACK_MELEE: case SKILL_BITE_OF_DEATH: case SKILL_UN_TRANSFORM: case SKILL_RAPID_GLIDING: break; default: GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(SkillType); pPlayer->sendPacket(&_GCSkillFailed1); dynamic_cast<Vampire*>(pCreature)->sendVampireSkillInfo(); return; } } BYTE X = pPacket->getX(); BYTE Y = pPacket->getY(); BYTE TX = pPacket->getTargetX(); BYTE TY = pPacket->getTargetY(); disableFlags(pCreature, pZone, SkillType); if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); SkillSlot* pSkillSlot = pSlayer->hasSkill(SkillType); bool bSuccess = true; if (pSkillSlot == NULL) bSuccess = false; if (SkillType == SKILL_INSTALL_MINE ) { bSuccess = true; TY = 0; } else { if (!isAbleToUseInventorySkill(pSlayer, X, Y, TX, TY)) bSuccess = false; } /* if (pSlayer->isFlag(Effect::EFFECT_CLASS_SNIPING_MODE)) { g_Sniping.checkRevealRatio(pSlayer, 20, 10); } */ if (bSuccess) { SkillHandler* pSkillHandler = g_pSkillHandlerManager->getSkillHandler(SkillType); Assert(pSkillHandler != NULL); pSkillHandler->execute(pSlayer, pPacket->getObjectID(), pPacket->getInventoryItemObjectID(), X, Y, TX, TY, pSkillSlot); } else { GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(SkillType); pPlayer->sendPacket(&_GCSkillFailed1); } } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); VampireSkillSlot* pVampireSkillSlot = pVampire->hasSkill(SkillType); bool bSuccess = true; if (pVampireSkillSlot == NULL) bSuccess = false; if (!isAbleToUseInventorySkill(pVampire, X, Y, TX, TY)) bSuccess = false; /* if (pVampire->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pVampire, true); } if (pVampire->isFlag(Effect::EFFECT_CLASS_EXTREME)) { EffectManager * pEffectManager = pVampire->getEffectManager(); Assert(pEffectManager != NULL); Effect * pEffect = pEffectManager->findEffect(Effect::EFFECT_CLASS_EXTREME); if (pEffect != NULL ) { pEffect->setDeadline(0); } } */ if (bSuccess) { SkillHandler* pSkillHandler = g_pSkillHandlerManager->getSkillHandler(SkillType); Assert(pSkillHandler != NULL); pSkillHandler->execute(pVampire, pPacket->getObjectID(), pPacket->getInventoryItemObjectID(), X, Y, TX, TY, pVampireSkillSlot); } else { GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(SkillType); pPlayer->sendPacket(&_GCSkillFailed1); } } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); OustersSkillSlot* pOustersSkillSlot = pOusters->hasSkill(SkillType); bool bSuccess = true; if (pOustersSkillSlot == NULL) bSuccess = false; if (!isAbleToUseInventorySkill(pOusters, X, Y, TX, TY)) bSuccess = false; if (bSuccess) { SkillHandler* pSkillHandler = g_pSkillHandlerManager->getSkillHandler(SkillType); Assert(pSkillHandler != NULL); pSkillHandler->execute(pOusters, pPacket->getObjectID(), pPacket->getInventoryItemObjectID(), X, Y, TX, TY, pOustersSkillSlot); } else { GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(SkillType); pPlayer->sendPacket(&_GCSkillFailed1); } } } #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void BloodDrain::execute(Vampire* pVampire, ObjectID_t TargetObjectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(vampire)" << endl; Assert(pVampire != 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는 공격할 수가 없다. // 면역 상태. by sigi. 2002.9.13 // 무적상태 체크. by sigi.2002.9.5 // 죽은 애는 피 빨 수 없다. by Sequoia.2003. 3. 20 if (pTargetCreature==NULL // NoSuch 제거. by sigi. 2002.5.2 || pTargetCreature->isNPC() || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN) || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) || pTargetCreature->isDead() ) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(vampire)" << endl; return; } GCBloodDrainOK1 _GCBloodDrainOK1; GCBloodDrainOK2 _GCBloodDrainOK2; GCBloodDrainOK3 _GCBloodDrainOK3; Timeval CurrentTime; getCurrentTime(CurrentTime); bool bHitRoll = HitRoll::isSuccessBloodDrain(pVampire, pTargetCreature); bool bCanHit = canHit(pVampire, pTargetCreature, SKILL_BLOOD_DRAIN); bool bTimeCheck = CurrentTime.tv_sec > 1 ? true : false; bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, 2); bool bPK = verifyPK(pVampire, pTargetCreature); if (bHitRoll && bCanHit && bTimeCheck && bRangeCheck && bPK) { // 슬레이어일 경우에만 이펙트 오브젝트를 생성한다. if (pTargetCreature->isSlayer()) { EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature); pEffectBloodDrain->setLevel(pVampire->getLevel()); pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION); // 3일?? pTargetCreature->addEffect(pEffectBloodDrain); pEffectBloodDrain->create(pTargetCreature->getName()); _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // 타겟이 뭐든 플래그는 건다. pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->sendRealWearingInfo(); pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2); // 로그를 남긴다. //log(LOG_BLOODDRAINED, pTargetCreature->getName(), pVampire->getName()); } // 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만.. // else if (pTargetCreature->isOusters() ) // { // EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature); // pEffectBloodDrain->setLevel(pVampire->getLevel()); // pTargetCreature->addEffect(pEffectBloodDrain); // pEffectBloodDrain->create(pTargetCreature->getName()); // _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // // // 타겟이 뭐든 플래그는 건다. // pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // // Sight_t oldSight = pTargetCreature->getSight(); // Sight_t newSight = pTargetCreature->getEffectedSight(); // // if (oldSight != newSight ) // { // pTargetCreature->setSight(newSight); // pZone->updateScan(pTargetCreature, oldSight, pTargetCreature->getSight()); // _GCBloodDrainOK2.addShortData(MODIFY_VISION, pTargetCreature->getSight()); // // GCChangeDarkLight gcChangeDarkLight; // gcChangeDarkLight.setDarkLevel(15); // gcChangeDarkLight.setLightLevel(newSight); // pTargetCreature->getPlayer()->sendPacket(&gcChangeDarkLight); // } // } // 타겟이 뭐든 플래그는 건다. pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // 올릴 경험치량을 계산한다. Exp_t Exp = computeCreatureExp(pTargetCreature, BLOODDRAIN_EXP); int targetLevel = 0; int targetMaxHP = 0; // 페임을 올려준다. if (pTargetCreature->isSlayer()) { //increaseFame(pVampire, Exp); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); targetLevel = pTargetSlayer->getHighestSkillDomainLevel(); targetMaxHP = pTargetSlayer->getHP(ATTR_MAX); } else if (pTargetCreature->isVampire()) { //increaseFame(pVampire, Exp); Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); targetLevel = pTargetVampire->getLevel(); targetMaxHP = pTargetVampire->getHP(ATTR_MAX); } else if (pTargetCreature->isOusters()) { //increaseFame(pOusters, Exp); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); targetLevel = pTargetOusters->getLevel(); targetMaxHP = pTargetOusters->getHP(ATTR_MAX); } else if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); Timeval NextTurn = pMonster->getNextTurn(); Timeval DelayTurn; DelayTurn.tv_sec = 4; DelayTurn.tv_usec = 500000; pMonster->addAccuDelay(DelayTurn); pMonster->addEnemy(pVampire); targetLevel = pMonster->getLevel(); targetMaxHP = pMonster->getHP(ATTR_MAX); } shareVampExp(pVampire, Exp, _GCBloodDrainOK1); // 흡혈을 하게 되면 흡혈한 사람의 체력이 올라간다. // Mephisto이펙트가 걸려있으면 HP는 안 올라간다. if (!pVampire->isFlag(Effect::EFFECT_CLASS_MEPHISTO)) { HP_t HealPoint = (Exp==0? computeBloodDrainHealPoint(pTargetCreature, BLOODDRAIN_EXP) : Exp); HP_t CurrentHP = pVampire->getHP(); HP_t MaxHP = pVampire->getHP(ATTR_MAX); HP_t NewHP = min((int)MaxHP , (int)CurrentHP + (int)HealPoint); // 은 데미지 관련 처리를 해 준다. Silver_t newSilverDamage = max(0, (int)pVampire->getSilverDamage()-(int)HealPoint); pVampire->saveSilverDamage(newSilverDamage); _GCBloodDrainOK1.addShortData(MODIFY_SILVER_DAMAGE, newSilverDamage); // 뱀파이어의 HP를 세팅한다. pVampire->setHP(NewHP); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pVampire->getObjectID()); gcStatusCurrentHP.setCurrentHP(NewHP); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &gcStatusCurrentHP, pVampire); _GCBloodDrainOK1.addShortData(MODIFY_CURRENT_HP, NewHP); } // 흡혈을 당한 애는 HP가 줄어든다. // 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage // by sigi. 2002.9.14 int drainDamage = 0; int myLevel = pVampire->getLevel(); if (targetLevel > myLevel) { drainDamage = targetMaxHP * (rand()%6+10) / 100; } else { // 레벨 5차이마다 1%씩 더~ int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel))); drainDamage = targetMaxHP * damagePercent / 100; } if (drainDamage > 0) { //decreaseHP(pZone, pTargetCreature, drainDamage, pVampire->getObjectID()); EffectDecreaseHP* pEffect = new EffectDecreaseHP(pTargetCreature); pEffect->setPoint(drainDamage); pEffect->setDeadline(20); // 2초 후 pEffect->setUserObjectID(pVampire->getObjectID()); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DECREASE_HP); } pVampire->getGQuestManager()->blooddrain(); // 흡혈시에도 성향 바뀜 // by sigi. 2002.12.16 // EffectDecreaseHP에서 HP가 닳아서 0이 되어야하는 경우가 있어서 // EffectDecreaseHP::unaffect()로 옮긴다. //computeAlignmentChange(pTargetCreature, drainDamage, pVampire, NULL, &_GCBloodDrainOK1); _GCBloodDrainOK1.setObjectID(TargetObjectID); _GCBloodDrainOK3.setObjectID(pVampire->getObjectID()); _GCBloodDrainOK3.setTargetObjectID (TargetObjectID); pPlayer->sendPacket(&_GCBloodDrainOK1); if (pTargetCreature != NULL && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer != NULL) { _GCBloodDrainOK2.setObjectID(pVampire->getObjectID()); // _GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION); pTargetPlayer->sendPacket(&_GCBloodDrainOK2); } } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &_GCBloodDrainOK3 , cList); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(vampire)" << endl; __END_CATCH }
void GroundBless::execute(Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pSkillSlot != 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, pSkillSlot->getSkillType()); return; } Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수 없다. // 저주 면역. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isOusters() ) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillInput input(pOusters, pSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pSkillSlot->getExpLevel()/2; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_GROUND_BLESS); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pOusters); // 이펙트 오브젝트를 생성해 붙인다. EffectGroundBless* pEffect = new EffectGroundBless(pTargetCreature); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_GROUND_BLESS); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); if (pTargetOusters != NULL ) pTargetOusters->initAllStatAndSend(); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(output.Duration); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3, cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4, cList); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer != NULL ) { if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_GROUND_BLESS); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void CGSelectWayPointHandler::execute(CGSelectWayPoint* pPacket , Player* pPlayer) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); static map<Level_t,Price_t> sPriceMap; try { int targetDynamicZoneType = g_pDynamicZoneInfoManager->getDynamicZoneTypeByZoneID(pPacket->getZoneID()); if (targetDynamicZoneType != DYNAMIC_ZONE_MAX) { executeEnterQuestZone(pPacket, pPlayer, targetDynamicZoneType); } // 게임 플레이어의 상태가 정상이 아니라면 걍 리턴한다. GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); if (pGamePlayer->getPlayerStatus() != GPS_NORMAL) return; // 크리쳐가 슬레이어가 아니라면 리턴한다. Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); Assert(pPC != NULL); if (pPC->getStore()->isOpen()) return; if (pCreature->hasRelicItem()) return; // 크리쳐가 죽었으면 리턴 if (pCreature->isDead()) return; // 초보존으로 들어가는 경우엔 종족 상관없이 보내준다. if (pPacket->getZoneID() == 1122) { ZONE_COORD pos(1122); if (pCreature->isSlayer()) { pos.x = 107; pos.y = 27; } else if (pCreature->isVampire()) { pos.x = 18; pos.y = 27; } else if (pCreature->isOusters()) { pos.x = 12; pos.y = 103; } else return; if (!canEnterBeginnerZone(pCreature)) return; // 초보존이 유료존일수도 있을라나...? #if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(pos.id); // 유료존인데 유료사용자가 아니면... if (pZoneInfo == NULL || ((pZoneInfo->isPayPlay() || pZoneInfo->isPremiumZone()) && (!pGamePlayer->isPayPlaying() && !pGamePlayer->isFamilyFreePass()))) { //Statement* pStmt = NULL; string connectIP = pGamePlayer->getSocket()->getHost(); // 유료 서비스 사용이 가능한가? if (pGamePlayer->loginPayPlay(connectIP, pGamePlayer->getID())) { sendPayInfo(pGamePlayer); } else if (pZoneInfo->isPayPlay()) { // 유료 서비스 사용 불가인 경우 GCSystemMessage gcSystemMessage; if (g_pConfig->getPropertyInt("IsNetMarble") == 0) { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); } else { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); } pGamePlayer->sendPacket(&gcSystemMessage); return; } } #endif pPC->getGQuestManager()->illegalWarp(); transportCreature(pCreature, pos.id, pos.x, pos.y, false); return; } if (pPacket->getZoneID() == 1131) { if (g_pVariableManager->getVariable(ACTIVE_LEVEL_WAR) == 0) { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); pGamePlayer->sendPacket(&gcSystemMessage); return; } /* if (g_pConfig->getPropertyInt("ServerID" ) != 0 ) { GCNoticeEvent gcNoticeEvent; gcNoticeEvent.setCode(NOTICE_EVENT_NOT_FIRST_SERVER); pGamePlayer->sendPacket(&gcNoticeEvent); // GCSystemMessage gcSystemMessage; // gcSystemMessage.setMessage(g_pStringPool->getString(STRID_LEVEL_WAR_ONLY_FIRST_SERVER )); // pGamePlayer->sendPacket (&gcSystemMessage); return; } */ // 크리쳐 정보 보고 알아서 튕겨주자 =_=;; ZONE_COORD pos(g_pLevelWarZoneInfoManager->getCreatureZoneID(pCreature )); if (g_pSweeperBonusManager->isAble(g_pLevelWarZoneInfoManager->getCreatureZoneID(pCreature))) { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_NO_WAR_IN_ACTIVE )); pGamePlayer->sendPacket (&gcSystemMessage); return; } if (pCreature->isSlayer()) { pos.x = 12; pos.y = 9; } else if (pCreature->isVampire()) { pos.x = 117; pos.y = 8; } else if (pCreature->isOusters()) { pos.x = 9; pos.y = 111; } #if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) Zone* pZone = getZoneByZoneID(pos.id); Assert(pZone != NULL); LevelWarManager* pLevelWarManager = pZone->getLevelWarManager(); Assert(pLevelWarManager != NULL); if (!pLevelWarManager->hasWar() && !g_pVariableManager->canEnterLevelWarZoneFree() && !pGamePlayer->isPayPlaying() && pGamePlayer->isFamilyFreePass() && !pLevelWarManager->canEnterFreeUser()) { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER_LEVEL_WAR_ZONE)); pGamePlayer->sendPacket(&gcSystemMessage); return; } #endif pPC->getGQuestManager()->illegalWarp(); transportCreature(pCreature, pos.id, pos.x, pos.y, false); return; } if (pPacket->getZoneID() == 72) { if (!g_pWarSystem->hasActiveRaceWar()) { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_NO_WAR_IN_ACTIVE)); pGamePlayer->sendPacket (&gcSystemMessage); return; } /* if (g_pConfig->getPropertyInt("ServerID" ) != 0 ) { GCNoticeEvent gcNoticeEvent; gcNoticeEvent.setCode(NOTICE_EVENT_NOT_FIRST_SERVER); pGamePlayer->sendPacket(&gcNoticeEvent); // GCSystemMessage gcSystemMessage; // gcSystemMessage.setMessage(g_pStringPool->getString(STRID_LEVEL_WAR_ONLY_FIRST_SERVER )); // pGamePlayer->sendPacket (&gcSystemMessage); return; } */ // 크리쳐 정보 보고 알아서 튕겨주자 =_=;; ZONE_COORD pos; if (pCreature->isSlayer()) { pos.id = 73; pos.x = 30; pos.y = 124; } else if (pCreature->isVampire()) { pos.id = 71; pos.x = 104; pos.y = 128; } else if (pCreature->isOusters()) { pos.id = 72; pos.x = 67; pos.y = 165; } /*#if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(pos.id); // 유료존인데 유료사용자가 아니면... if (pZoneInfo==NULL || (pZoneInfo->isPayPlay() || pZoneInfo->isPremiumZone()) && (!pGamePlayer->isPayPlaying() && !pGamePlayer->isFamilyFreePass() )) { //Statement* pStmt = NULL; string connectIP = pGamePlayer->getSocket()->getHost(); // 유료 서비스 사용이 가능한가? if (pGamePlayer->loginPayPlay(connectIP, pGamePlayer->getID())) { sendPayInfo(pGamePlayer); } else if (pZoneInfo->isPayPlay()) { // 유료 서비스 사용 불가인 경우 GCSystemMessage gcSystemMessage; if (g_pConfig->getPropertyInt("IsNetMarble")==0) { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER )); } else { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER )); } pGamePlayer->sendPacket (&gcSystemMessage); return; } } #endif*/ if (!g_pVariableManager->isActiveRaceWarLimiter() || pCreature->isFlag(Effect::EFFECT_CLASS_RACE_WAR_JOIN_TICKET)) { pPC->getGQuestManager()->illegalWarp(); transportCreature(pCreature, pos.id, pos.x, pos.y, false); return; } else { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER_DURING_RACE_WAR)); pGamePlayer->sendPacket(&gcSystemMessage); return; } } if (!pCreature->isSlayer() && !pCreature->isOusters()) { // 뭔가를 해야하지 않을까? return; } if (pCreature->isFlag(Effect::EFFECT_CLASS_HAS_FLAG)) { // 뭔가를 해야하지 않을까? return; } if (pCreature->isFlag(Effect::EFFECT_CLASS_HAS_SWEEPER)) { // 뭔가를 해야하지 않을까? return; } //Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); //Assert(pSlayer != NULL); bool bCancel = false; // 이펙트가 걸려있어야 정상적인 이동이다. if (pCreature->isOusters() || (pCreature->isSlayer() && pCreature->isFlag(Effect::EFFECT_CLASS_SLAYER_PORTAL))) { ZoneID_t id = pPacket->getZoneID(); ZoneCoord_t x = pPacket->getX(); ZoneCoord_t y = pPacket->getY(); if (id == 0 && x == 0 && y == 0) { bCancel = true; } else { // 석화 상태일 경우 생깐다. if (pCreature->isFlag(Effect::EFFECT_CLASS_PARALYZE)) { bCancel = true; } // 웨이포인트 매니저를 통해서 클라이언트가 보내온 // 웨이포인트가 정상적인 웨이포인트인지를 검증한다. if (!g_pWayPointManager->isValidWayPoint(id, x, y, pCreature->getRace())) { // 뭔가를 해야하지 않을까? bCancel = true; //return; } try { if (!bCancel) { #if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(id); // 유료존인데 유료사용자가 아니면... if (pZoneInfo==NULL || ((pZoneInfo->isPayPlay() || pZoneInfo->isPremiumZone()) && (!pGamePlayer->isPayPlaying() && !pGamePlayer->isFamilyFreePass()))) { //Statement* pStmt = NULL; string connectIP = pGamePlayer->getSocket()->getHost(); // 유료 서비스 사용이 가능한가? if (pGamePlayer->loginPayPlay(connectIP, pGamePlayer->getID())) { sendPayInfo(pGamePlayer); } else if (pZoneInfo->isPayPlay()) { // 유료 서비스 사용 불가인 경우 GCSystemMessage gcSystemMessage; if (g_pConfig->getPropertyInt("IsNetMarble") == 0) { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); } else { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER)); } pGamePlayer->sendPacket (&gcSystemMessage); bCancel = true; } } #endif if (!bCancel) { // 이동시키기 전에 이펙트를 삭제한다. if (pCreature->isSlayer()) pCreature->removeFlag(Effect::EFFECT_CLASS_SLAYER_PORTAL); if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); Assert(pOusters != NULL); GCNoticeEvent gcNoticeEvent; // 대지정령의 뿔을 사용할라면 시오람과 계약을 맺었어야 한다. if (!pOusters->getFlagSet()->isOn(FLAGSET_GNOMES_HORN)) { gcNoticeEvent.setCode(NOTICE_EVENT_CONTRACT_GNOMES_HORN); pPlayer->sendPacket(&gcNoticeEvent); return; } Level_t level = pOusters->getLevel(); Price_t price = sPriceMap[level]; if (price == 0) { price = (Price_t)(pow((double)level, 1.3) * 100) / 2; sPriceMap[level] = price; } /*if (g_pFlagManager->hasFlagWar() && pPacket->getZoneID() == 32 && pPacket->getX() == 124 && pPacket->getY() == 144 ) price = 0;*/ if (pOusters->getGold() < price) { gcNoticeEvent.setCode(NOTICE_EVENT_NOT_ENOUGH_MONEY); pPlayer->sendPacket(&gcNoticeEvent); return; } else { pOusters->decreaseGoldEx(price); GCModifyInformation gcMI; gcMI.addLongData(MODIFY_GOLD, pOusters->getGold()); pPlayer->sendPacket(&gcMI); } } // 올바른 웨이포인트라면 슬레이어를 이동시켜준다. pPC->getGQuestManager()->illegalWarp(); transportCreature(pCreature, id, x, y, false); } } } catch (NoSuchElementException&) { bCancel = true; } } } if (bCancel && pCreature->isSlayer()) { Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); // id, x, y가 모두 0일 경우 이동을 취소한다는 뜻이다. pCreature->removeFlag(Effect::EFFECT_CLASS_SLAYER_PORTAL); // 헬기를 제거하라고 뿌려준다. GCAddHelicopter gcAddHelicopter; gcAddHelicopter.setObjectID(pCreature->getObjectID()); gcAddHelicopter.setCode(1); pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcAddHelicopter); } } catch (Throwable & t) { cerr << t.toString() << endl; } #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
void EffectStormPoison::affect(Creature* pCreature) throw(Error) { __BEGIN_TRY //cout << "EffectStormPoison " << "begin" << endl; Assert(pCreature != NULL); Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); // 사용자를 가져온다. // !! 이미 존을 나갔을 수 있으므로 NULL이 될 수 있다. // by bezz. 2003.3.13 Creature* pCastCreature = pZone->getCreature(m_UserObjectID); // 캐스터가 없으면 무시한다. if (pCastCreature == NULL ) return; // EffectStormPoison은 AcidStorm, PoisonStorm, BloodyStorm위를 지나갈때 붙는다. // 이는 3번의 연속 데미지를 주고 사라진다. Damage_t StormDamage = m_Point; GCModifyInformation GCAttackerMI; if (!(pZone->getZoneLevel() & COMPLETE_SAFE_ZONE) // 무적상태 체크. by sigi. 2002.9.5 && canAttack(pCastCreature, pCreature ) ) { if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); GCModifyInformation gcMI; setDamage(pSlayer, StormDamage, pCastCreature, SKILL_POISON_STORM, &gcMI, &GCAttackerMI); pSlayer->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isVampire()) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); GCModifyInformation gcMI; setDamage(pVampire, StormDamage, pCastCreature, SKILL_POISON_STORM, &gcMI, &GCAttackerMI); pVampire->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); GCModifyInformation gcMI; setDamage(pOusters, StormDamage, pCastCreature, SKILL_POISON_STORM, &gcMI, &GCAttackerMI); pOusters->getPlayer()->sendPacket(&gcMI); } else if (pCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pCreature); setDamage(pMonster, StormDamage, pCastCreature, SKILL_POISON_STORM, NULL, &GCAttackerMI); } if (pCastCreature->isVampire() && pCreature->isDead() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pCastCreature); int exp = computeCreatureExp(pCreature, KILL_EXP); shareVampExp(pVampire, exp, GCAttackerMI); pVampire->getPlayer()->sendPacket(&GCAttackerMI); } // m_CasterName이 pCreature를 죽인 경우의 KillCount 처리 // by sigi. 2002.9.9 // set damage 를 불러서 처리한다. 주석 처리 // by bezz. 2002.12.31 /* if (pCreature->isDead()) { Creature* pAttacker = pZone->getCreature(m_UserObjectID); if (pAttacker!=NULL) { affectKillCount(pAttacker, pCreature); } }*/ } setNextTime(m_Tick); //cout << "EffectStormPoison " << "end" << endl; __END_CATCH }
void CGTradeAddItemHandler::executeOusters (CGTradeAddItem* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // 상위 함수에서 에러를 검사했기 때문에, // 여기서는 포인터가 널인지를 검사하지 않는다. ObjectID_t TargetOID = pPacket->getTargetObjectID(); ObjectID_t ItemOID = pPacket->getItemObjectID(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pPC = pGamePlayer->getCreature(); Zone* pZone = pPC->getZone(); PlayerCreature* pTargetPC = dynamic_cast<PlayerCreature*>(pZone->getCreature(TargetOID)); // NoSuch제거. by sigi. 2002.5.2 if (pTargetPC==NULL) return; Ousters* pSender = dynamic_cast<Ousters*>(pPC); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); // 교환 대상에 추가할 아이템의 포인터를 얻어낸다. CoordInven_t X, Y; Inventory* pInventory = pSender->getInventory(); Item* pItem = pInventory->findItemOID(ItemOID, X, Y); // 추가할 아이템이 없다면 당연히 더 이상 처리가 불가능 // Relic은 교환할 수 없다. if (pItem == NULL || !canTrade(pItem ) || pSender->getStore()->hasItem(pItem) || (pItem->getItemClass() == Item::ITEM_CLASS_SUB_INVENTORY && hasItemWithItemClass(pTargetPC, Item::ITEM_CLASS_SUB_INVENTORY ) ) ) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_ADD_ITEM); return; } // //#ifdef __XMAS_EVENT_CODE__ // 녹색 선물 상자인 경우에는, 상대방에게 적색 선물 상자가 없는지 검사한 후, // 인증 패킷을 보내줘야 한다. if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX) { PlayerCreature* pReceiver = dynamic_cast<PlayerCreature*>(pTargetPC); Item* pExtraSlotItem = pReceiver->getExtraInventorySlotItem(); if (pItem->getItemType() == 0) { Inventory* pTargetInventory = pReceiver->getInventory(); if (pTargetInventory->hasRedGiftBox()) { // 적색 선물 상자를 가지고 있다면 더할 수 없다. 리턴시킨다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } else if (pExtraSlotItem != NULL) { if (pExtraSlotItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pExtraSlotItem->getItemType() == 1) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } else { // 적색 선물 상자를 가지고 있지 않다면, 걍 넘어간다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } } else if (pItem->getItemType() == 1) { // 적색 선물 상자는 교환 품목이 될 수 없다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } //#endif // TradeInfo* pInfo1 = pTradeManager->getTradeInfo(pSender->getName()); TradeInfo* pInfo2 = pTradeManager->getTradeInfo(pTargetPC->getName()); list<Item*> tradeList1 = pInfo1->getItemList(); if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pItem->getItemType() > 1 && pItem->getItemType() < 6) { for (list<Item*>::iterator itr = tradeList1.begin(); itr != tradeList1.end(); itr++) { Item* pTradeItem = (*itr); if (pTradeItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pTradeItem->getItemType() > 1 && pTradeItem->getItemType() < 6) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } else if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pItem->getItemType() >= 6) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } // TradeManager에 교환 대상으로서 아이템을 더한다. //Assert(pInfo1->addItem(pItem)); pInfo1->addItem(pItem); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { //cout << "CGTradeRemoveItem [" << pSender->getName() << "]의 상태가 TRADE_FINISH이므로, 인증 패킷을 보내준다." << endl; // 인증 패킷을 날려준다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_WHEN_ACCEPT); pPlayer->sendPacket(&gcTradeVerify); } else { //cout << "CGTradeRemoveItem [" << pSender->getName() << "]의 상태가 TRADE_FINISH가 아니므로, 인증 패킷 날리지 않는다." << endl; } // 아이템을 더하거나 뺄 경우, 상태가 TRADE_FINISH라면 // TRADE_TRADING으로 바꿔줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 상대방에게 날려줄 아이템 정보를 구성한다. GCTradeAddItem gcTradeAddItem; makeGCTradeAddItemPacket(&gcTradeAddItem, pSender->getObjectID(), pItem, X, Y); // 상대방에게 교환할 아이템 정보를 날려준다. Player* pTargetPlayer = pTargetPC->getPlayer(); pTargetPlayer->sendPacket(&gcTradeAddItem); #endif __END_DEBUG_EX __END_CATCH }
//////////////////////////////////////////////////////////////////////////////// // 액션을 실행한다. //////////////////////////////////////////////////////////////////////////////// void ActionEnterGDRLair::execute (Creature * pNPC , Creature * pCreature) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG Assert(pCreature != NULL); Assert(pCreature->isPC()); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pCreature->getPlayer()); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); Assert(pPC != NULL); ZoneID_t zoneID; ZoneCoord_t X, Y; if (m_PortalID == GDRLairManager::Instance().getCorrectPortal() ) { zoneID = 1412; X = 142; Y = 169; } else { zoneID = 1411; X = 125; Y = 58; } bool bTransport = true; #if defined(__PAY_SYSTEM_ZONE__) || defined(__PAY_SYSTEM_FREE_LIMIT__) try { ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(zoneID); // 유료존인데 유료사용자가 아니면... if (pZoneInfo==NULL || pZoneInfo->isPayPlay() && !pGamePlayer->isPayPlaying()) { string connectIP = pGamePlayer->getSocket()->getHost(); // 유료 서비스 사용이 가능한가? if (pGamePlayer->loginPayPlay(connectIP, pGamePlayer->getID())) { sendPayInfo(pGamePlayer); } else { // 유료 서비스 사용 불가인 경우 GCSystemMessage gcSystemMessage; if (g_pConfig->getPropertyInt("IsNetMarble")==0) { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER_PAY_ZONE )); } else { gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER )); } pGamePlayer->sendPacket (&gcSystemMessage); bTransport = false; return; } } } catch (NoSuchElementException&) { } #endif if (bTransport) { if (pPC->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pPC); Assert(pSlayer != NULL); // 오토바이를 타고 있으면 오토바이에서 내린다. if (pSlayer->hasRideMotorcycle() ) { pSlayer->getOffMotorcycle(); } } if (pPC->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pPC); Assert(pOusters != NULL); // 실프 타고 있으면 내려준다 if (pOusters->isFlag(Effect::EFFECT_CLASS_SUMMON_SYLPH) ) { Effect* pEffect = pOusters->findEffect(Effect::EFFECT_CLASS_SUMMON_SYLPH); if (pEffect != NULL ) pEffect->setDeadline(0); } } if (pPC->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pPC); Assert(pVampire != NULL); if (pVampire->isFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_BAT) ) { addUntransformCreature(pVampire->getZone(), pVampire, true); } } Effect* pEffect = pPC->findEffect(Effect::EFFECT_CLASS_CAN_ENTER_GDR_LAIR); if (pEffect != NULL ) pEffect->setDeadline(0); transportCreature(pCreature, zoneID, X, Y, true); } else { GCSystemMessage gcSystemMessage; gcSystemMessage.setMessage(g_pStringPool->getString(STRID_CANNOT_ENTER )); pGamePlayer->sendPacket (&gcSystemMessage); } __END_DEBUG __END_CATCH }