////////////////////////////////////////////////////////////////////////////// // (nx,ny)·Î À̵¿ÇÒ ¼ö Àִ°¡? ////////////////////////////////////////////////////////////////////////////// bool Creature::canMove (ZoneCoord_t nx , ZoneCoord_t ny) const throw(Error) { Assert(m_pZone != NULL); // ¿Ã¹Ù¸¥ ÁÂÇ¥Àΰ¡? // ¸·ÇôÀÖÁö´Â ¾ÊÀº°¡? if (//isFlag(Effect::EFFECT_CLASS_SANCTUARY) // m_Flag.test(Effect::EFFECT_CLASS_SANCTUARY) m_Flag.test(Effect::EFFECT_CLASS_POISON_MESH) || m_Flag.test(Effect::EFFECT_CLASS_TENDRIL) || m_Flag.test(Effect::EFFECT_CLASS_BLOODY_WALL_BLOCKED) || m_Flag.test(Effect::EFFECT_CLASS_CASKET) || !isValidZoneCoord(m_pZone, nx, ny)) return false; /* // ¼º¹°À» °¡Áö°í ÀÖ´Â °æ¿ì¶ó¸é.. if (m_Flag.test(Effect::EFFECT_CLASS_HAS_SLAYER_RELIC) || m_Flag.test(Effect::EFFECT_CLASS_HAS_VAMPIRE_RELIC)) { ZoneLevel_t ZoneLevel = m_pZone->getZoneLevel(nx, ny); // ½½·¹À̾îÀÌ¸é ½½·¹ÀÌ¾î ¾ÈÀüÁö´ë¿¡ ¸ø µé¾î°£´Ù. // ¹ìÆÄÀ̾îÀÌ¸é ¹ìÆÄÀ̾î¾ÈÀüÁö´ë¿¡ ¸ø µé¾î°£´Ù. // °øÅë ¾ÈÀüÁö´ëÀÌ¸é ¸ø µé¾î°£´Ù. if (isSlayer() && (ZoneLevel & SLAYER_SAFE_ZONE) || isVampire() && (ZoneLevel & VAMPIRE_SAFE_ZONE) || (ZoneLevel & COMPLETE_SAFE_ZONE)) { return false; } } */ Tile& rTile = m_pZone->getTile(nx,ny); if (rTile.isBlocked(m_MoveMode) // BloodyWallBlock³ª // Sanctuary ÀÌÆåÆ®°¡ °É·ÁÀÖ´Ù¸é ¸ø °£´Ù. || rTile.hasEffect() && (rTile.getEffect(Effect::EFFECT_CLASS_BLOODY_WALL_BLOCKED) || rTile.getEffect(Effect::EFFECT_CLASS_SANCTUARY)) ) { return false; } Tile& rNewTile = m_pZone->getTile(getX(), getY()); if (rNewTile.getEffect(Effect::EFFECT_CLASS_SANCTUARY) ) return false; return true; }
////////////////////////////////////////////////////////////////////////////// // (nx,ny)ÀÌ ¸Ê¿¡ ÀÇÇØ ¸·È÷´Â°¡? ////////////////////////////////////////////////////////////////////////////// bool Creature::isBlockedByCreature (ZoneCoord_t nx , ZoneCoord_t ny) const throw(Error) { Assert(m_pZone != NULL); // ¿Ã¹Ù¸¥ ÁÂÇ¥Àΰ¡? // °°Àº ¹«µå ¸ðµåÀÇ Å©¸®ÃÄ°¡ Á¸ÀçÇÏÁö ¾Ê´Â°¡? if (!isValidZoneCoord(m_pZone, nx, ny) || !m_pZone->getTile(nx,ny).hasCreature(m_MoveMode)) return false; return true; }
//---------------------------------------------------------------------- // remove effect from target //---------------------------------------------------------------------- void EffectDecayMotorcycle::unaffect (Zone* pZone , ZoneCoord_t x , ZoneCoord_t y , Object* pTarget, Slayer* pSlayer) throw(Error) { __BEGIN_TRY // 올바른 좌표이어야 한다. Assert(isValidZoneCoord(pZone, x, y)); // TempItem 변수를 잡는다. Item* pTempItem = NULL; // 여기서는 지정 아이템이 없을 수 있으며, 또 다른 아이템이 놓여 있을 수도 있다. // 이 경우는 오리지널 아이템과 지금 현재 바닥에 있는 아이템을 비교하여 삭제해야 한다. // 없을 경우는 무시하면 된다. Tile & tile = pZone->getTile(x, y); if (tile.hasItem()) { pTempItem = tile.getItem(); if (pTempItem != NULL) { // ObjectID가 같다는 말은 같은 아이템이란 말이다. //if (pTempItem->getObjectID() == m_ObjectID) { if (pTempItem->getObjectID() == m_ObjectID) { pZone->deleteItem(pTempItem , x, y); // 아이템이 사라졌다는 패킷을 날린다. GCDeleteObject gcDeleteObject; gcDeleteObject.setObjectID(m_ObjectID); pZone->broadcastPacket(x, y , &gcDeleteObject); if (m_bDeleteFromDB) { pTempItem->destroy(); } SAFE_DELETE(pTempItem); } } } // heartbeat시 EffectDecayMotorcycle이 처리된다. 그 이후 다음 heartbeat시에 // 사용자에게 오토바이를 호출해 주어야 한다. // 사용자는 오토바이의 오브젝트와 //EffectCallMotorcycle* pEffectCallMotorcycle = new EffectCallMotorcycle(pMotorcycleObject, pSlayer); //pTarget = NULL; __END_CATCH }
void EffectDestinies::affect() throw(Error) { __BEGIN_TRY setDeadline(0); Creature* pCaster = dynamic_cast<Creature*>(m_pTarget); int cx = pCaster->getX(); int cy = pCaster->getY(); Zone* pZone = pCaster->getZone(); for (int i=-8; i<=8; ++i ) for (int j=-8; j<=8; ++j ) { int tx = cx + i; int ty = cy + j; if (tx < 0 || ty < 0 ) continue; if (!isValidZoneCoord(pZone, tx, ty ) ) continue; list<Object*>& olist = pZone->getTile(tx, ty).getObjectList(); list<Object*>::iterator itr = olist.begin(); for (; itr != olist.end() ; ++itr ) { Object* pObject = *itr; if (pObject == NULL || pObject->getObjectClass() != Object::OBJECT_CLASS_CREATURE ) continue; Creature* pCreature = dynamic_cast<Creature*>(pObject); if (pCreature == NULL ) continue; bool isTarget = false; if (pCreature->getCreatureClass() == m_TargetClass ) { isTarget = true; if (m_TargetClass == Creature::CREATURE_CLASS_MONSTER ) { Monster* pTargetMonster = dynamic_cast<Monster*>(pCreature); if (pTargetMonster->getSpriteType() != m_TargetSpriteType ) isTarget = false; } } if (isTarget ) affect(pCreature); } } //cout << "EffectDestinies" << "affect BEGIN" << endl; __END_CATCH }
void EffectPKZoneRegen::affect() throw(Error) { __BEGIN_TRY Assert(m_pZone != NULL); Assert(isValidZoneCoord(m_pZone, m_Rect.left, m_Rect.top )); Assert(isValidZoneCoord(m_pZone, m_Rect.right, m_Rect.bottom )); for (ZoneCoord_t X = m_Rect.left ; X <= m_Rect.right ; X++ ) { for (ZoneCoord_t Y = m_Rect.top ; Y <= m_Rect.bottom ; Y++ ) { Tile& tile = m_pZone->getTile(X, Y); const list<Object*>& oList = tile.getObjectList(); for (list<Object*>::const_iterator itr = oList.begin() ; itr != oList.end() ; itr++ ) { Object* pTargetObject = (*itr); if (pTargetObject != NULL && pTargetObject->getObjectClass() == Object::OBJECT_CLASS_CREATURE ) { Creature* pCreature = dynamic_cast<Creature*>(pTargetObject); Assert(pCreature != NULL); affect(pCreature); } } } } setNextTime(m_Turn); __END_CATCH }
void EffectDecayCorpse::unaffect (Zone* pZone , ZoneCoord_t x , ZoneCoord_t y , Object* pTarget) throw(Error) { __BEGIN_TRY // 올바른 좌표이어야 한다. Assert(isValidZoneCoord(pZone, x, y)); // 시체에 접근한다. if (pZone->getTile(x,y).hasItem()) { Item* pItem = pZone->getTile(x,y).getItem(); if (pItem != NULL) { // 타일위에 아이템이 있고 그 아이템의 오브젝트 아이디가 똑같아야만 똑 같은 시체이다. if (pItem->getObjectID() == m_ObjectID) { Corpse* pCorpse = dynamic_cast<Corpse*>(pTarget); try { // 시체를 존에서 삭제한다. Assert(pZone->getTile(x,y).getItem() == pCorpse); pZone->deleteItem(pCorpse , x, y); } catch (NoSuchElementException & nsee) { cerr << "EffectDecayCorpse::unaffect() : NoSuchElementException" << endl; throw Error(nsee.toString()); } GCDeleteObject gcDeleteObject; gcDeleteObject.setObjectID(pCorpse->getObjectID()); pZone->broadcastPacket(x, y , &gcDeleteObject); // 시체 자체를 삭제한다. SAFE_DELETE(pCorpse); } } } pTarget = NULL; __END_CATCH }
//---------------------------------------------------------------------- // remove effect from target //---------------------------------------------------------------------- void EffectDeleteItem::unaffect (Zone* pZone , ZoneCoord_t x , ZoneCoord_t y , Object* pTarget) throw(Error) { __BEGIN_TRY // 올바른 좌표이어야 한다. //Assert(pTarget!=NULL); Assert(isValidZoneCoord(pZone, x, y)); //pZone->deleteFromItemList(pTarget->getObjectID()); //(pZone->getTile(x, y)).deleteItem(); //pZone->deleteItem(pTarget, x, y); Item* pItem = NULL; Tile& tile = pZone->getTile(x,y); if (tile.hasItem() ) { pItem = tile.getItem(); if (pItem != NULL ) { if (pItem->getObjectID() == m_ObjectID ) { pZone->deleteItem(pItem, x, y); GCDeleteObject gcDO; gcDO.setObjectID(pTarget->getObjectID()); pZone->broadcastPacket(x, y, &gcDO); SAFE_DELETE(pTarget); } } } __END_CATCH }
//---------------------------------------------------------------------- // remove effect from target //---------------------------------------------------------------------- void EffectDecayItem::unaffect (Zone* pZone , ZoneCoord_t x , ZoneCoord_t y , Object* pTarget) throw(Error) { __BEGIN_TRY // 올바른 좌표이어야 한다. Assert(isValidZoneCoord(pZone, x, y)); // TempItem 변수를 잡는다. Item* pTempItem = NULL; // 여기서는 지정 아이템이 없을 수 있으며, 또 다른 아이템이 놓여 있을 수도 있다. // 이 경우는 오리지널 아이템과 지금 현재 바닥에 있는 아이템을 비교하여 삭제해야 한다. // 없을 경우는 무시하면 된다. Tile & tile = pZone->getTile(x, y); if (tile.hasItem()) { pTempItem = tile.getItem(); if (pTempItem != NULL) { // ObjectID가 같다는 말은 같은 아이템이란 말이다. //if (pTempItem->getObjectID() == m_ObjectID) { if (pTempItem->getObjectID() == m_ObjectID) { pZone->deleteItem(pTempItem , x, y); // 아이템이 사라졌다는 패킷을 날린다. GCDeleteObject gcDeleteObject; gcDeleteObject.setObjectID(m_ObjectID); pZone->broadcastPacket(x, y , &gcDeleteObject); if (m_bDeleteFromDB) { //ItemInfo* pItemInfo = g_pItemInfoManager->getItemInfo(pTempItem->getItemClass(), pTempItem->getItemType()); //Assert(pItemInfo!=NULL); // 유니크 아이템인 경우 개수를 줄인다. if (pTempItem->isUnique()) { // create한 아이템이 아닌 경우만 지워준다. if (pTempItem->getCreateType()!=Item::CREATE_TYPE_CREATE) UniqueItemManager::deleteItem(pTempItem->getItemClass(), pTempItem->getItemType()); filelog("uniqueItem.txt", "[EffectDecayItem] %s", pTempItem->toString().c_str()); } // ItemTraceLog 를 남긴다 /* * 존에 떨어진 아이템중 expire time인것들 모두 로그를 빼버린다. if (pTempItem != NULL && pTempItem->isTraceItem() ) { char zoneName[15]; sprintf(zoneName, "%4d%3d%3d", pZone->getZoneID(), x, y); remainTraceLog(pTempItem, zoneName, "GOD", ITEM_LOG_DELETE, DETAIL_TIMEOUT); } */ // 돈 로그 남기자 if (pTempItem->getItemClass() == Item::ITEM_CLASS_MONEY ) { Money* pMoney = dynamic_cast<Money*>(pTempItem); if (pMoney->getAmount() >= g_pVariableManager->getMoneyTraceLogLimit() ) { char zoneName[15]; sprintf(zoneName, "%4d%3d%3d", pZone->getZoneID(), x, y); remainMoneyTraceLog(zoneName, "GOD", ITEM_LOG_DELETE, DETAIL_TIMEOUT, pMoney->getAmount()); } } pTempItem->destroy(); } SAFE_DELETE(pTempItem); } } } pTarget = NULL; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // // 모터 사이클을 처리한다. // ////////////////////////////////////////////////////////////////////////////// void CGShopRequestSellHandler::executeMotorcycle (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); 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); int CenterX = pNPC->getX(); int CenterY = pNPC->getY(); // 플레이어가 팔려고 하는 아이템을 가지고 있는지 검사 Inventory* pInventory = pPC->getInventory(); Gold_t playerMoney = pPC->getGold(); Item* pItem = pInventory->getItemWithObjectID(ITEMOID); if (pItem == NULL) return sendFailPacket(pPacket, pPlayer); // 주위 일정 범위를 검색해서, 모터 사이클이 있는지 확인한다. 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.hasItem()) { Item* pItemOnTile = tile.getItem(); if (pItemOnTile == NULL) continue; // 만일 아이템이 타일 위에 있을 경우, 모터 사이클인지 확인한다. if (pItemOnTile->getItemClass() == Item::ITEM_CLASS_MOTORCYCLE) { DWORD targetID = dynamic_cast<Key*>(pItem)->getTarget(); ItemID_t motorcycleID = pItemOnTile->getItemID(); if (targetID == motorcycleID) { // 모터사이클을 DB에서 삭제한다. pItemOnTile->destroy(); // 플레이어의 인벤토리에서 열쇠를 제거한다. pInventory->deleteItem(ITEMOID); pItem->destroy(); SAFE_DELETE(pItem); // 열쇠 값이 아니라, 오토바이 값을 줘야 한다. Price_t itemPrice = g_pPriceManager->getPrice(pItemOnTile, pNPC->getMarketCondBuy(), SHOP_RACK_NORMAL, pPC); // 플레이어의 돈을 늘린다. //pPC->setGoldEx(playerMoney+itemPrice); // by sigi. 2002.9.4 pPC->increaseGoldEx(itemPrice); // 물건을 판 플레이어에게 GCShopSellOK를...보낸다. GCShopSellOK okpkt; okpkt.setObjectID(NPCID); if (!pItemOnTile->getOptionTypeList().empty()) okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL)); else okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL)); okpkt.setItemObjectID(ITEMOID); okpkt.setPrice(playerMoney+itemPrice); pPlayer->sendPacket(&okpkt); // 뻑킹 센터에서 박스를 삭제해 준다. if (g_pParkingCenter->hasMotorcycleBox(motorcycleID)) g_pParkingCenter->deleteMotorcycleBox(motorcycleID); // NPC에게 자리가 충분하다면 플레이어가 판 아이템을 보관한다. // 단 스페셜 아이템만을 보관한다. 노말 아이템은 그냥 버림. //if (pItemOnTile->getOptionType() != 0) //{ // index = pNPC->getFirstEmptySlot(SHOP_RACK_SPECIAL); // if (index < SHOP_RACK_INDEX_MAX) // { // pNPC->insertShopItem(SHOP_RACK_SPECIAL, index, pItemOnTile); // // 스페셜 아이템을 NPC가 진열장에 추가했으므로, 상점 버전이 올라간다. // pNPC->increaseShopVersion(SHOP_RACK_SPECIAL); // } //} //else //{ // SAFE_DELETE(pItemOnTile); //} // 모터 사이클을 찾았으므로, 할 일이 끝났다. return; } } } } // 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()); } // FOR 루프를 다 돌고, 이까지 왔다는 것은 근처에 오토바이가 없다는 말이당... // 그러므로 모터 사이클 팔기가 실패했다는 것을 알린다. GCShopSellFail failpkt; failpkt.setObjectID(NPCID); pPlayer->sendPacket(&failpkt); #endif __END_DEBUG_EX __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 EffectCureCriticalWounds::affect(Creature* pCreature) throw(Error) { __BEGIN_TRY Zone* pZone = pCreature->getZone(); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; int X = pCreature->getX(); int Y = pCreature->getY(); Exp_t ExpUp = 0; bool bCured = false; for(int oY = -2; oY <= 2; oY++) for(int oX = -2; oX <= 2; oX++) { int tileX = X+oX; int tileY = Y+oY; if (isValidZoneCoord(pZone, tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.hasCreature(Creature::MOVE_MODE_WALKING ) ) { const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; Creature* pTargetCreature = NULL; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE && (pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer()) { Assert(pTargetCreature != NULL); HP_t RemainHP = 0; if (pTargetCreature->isSlayer() && !pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature); HP_t CurrentHP = pSlayer->getHP(ATTR_CURRENT); HP_t MaxHP = pSlayer->getHP(ATTR_MAX); if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN)) { ExpUp++; Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN); EffectBloodDrain * pEffectBloodDrain = dynamic_cast<EffectBloodDrain*>(pEffect); Assert(pEffectBloodDrain != NULL); if (pEffectBloodDrain->getLevel() < CriticalBloodDrainLevel ) { // 흡혈 아르바이트를 방지하기 위한 후유증 이펙트를 붙여준다. if (pSlayer->isFlag(Effect::EFFECT_CLASS_AFTERMATH)) { Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_AFTERMATH); EffectAftermath* pEffectAftermath = dynamic_cast<EffectAftermath*>(pEffect); pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다. } else { EffectAftermath* pEffectAftermath = new EffectAftermath(pSlayer); pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다. pSlayer->addEffect(pEffectAftermath); pSlayer->setFlag(Effect::EFFECT_CLASS_AFTERMATH); pEffectAftermath->create(pSlayer->getName()); } pEffectBloodDrain->destroy(pSlayer->getName()); pSlayer->deleteEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN); bCured = true; SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->sendModifyInfo(prev); GCRemoveEffect gcRemoveEffect; gcRemoveEffect.setObjectID(pSlayer->getObjectID()); gcRemoveEffect.addEffectList((EffectID_t)Effect::EFFECT_CLASS_BLOOD_DRAIN); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcRemoveEffect); } } if(CurrentHP < MaxHP ) { ExpUp++; bCured = true; RemainHP = min(CurrentHP + m_Point,(int)MaxHP); pSlayer->setHP(RemainHP, ATTR_CURRENT); GCModifyInformation gcMI; gcMI.addShortData(MODIFY_CURRENT_HP, RemainHP); pSlayer->getPlayer()->sendPacket(&gcMI); _GCSkillToSelfOK1.setSkillType(SKILL_CURE_EFFECT); _GCSkillToSelfOK1.setDuration(0); pSlayer->getPlayer()->sendPacket(&_GCSkillToSelfOK1); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SKILL_CURE_EFFECT); _GCSkillToSelfOK2.setDuration(0); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &_GCSkillToSelfOK2, pTargetCreature); Zone* pZone = pTargetCreature->getZone(); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pTargetCreature->getObjectID()); gcStatusCurrentHP.setCurrentHP(RemainHP); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcStatusCurrentHP); } } } } } } } SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SKILL_CURE_CRITICAL_WOUNDS); if(pSkillInfo != NULL && bCured ) { SkillSlot * pSkillSlot = ((Slayer*)pCreature)->hasSkill(SKILL_CURE_CRITICAL_WOUNDS); if(pSkillSlot != NULL ) { Slayer * pCastSlayer = dynamic_cast<Slayer*>(pCreature); GCModifyInformation gcMI; SkillDomainType_t DomainType = pSkillInfo->getDomainType(); // 경험치를 올려준다. shareAttrExp(pCastSlayer, ExpUp, 1 , 1 , 8, gcMI); increaseDomainExp(pCastSlayer, DomainType, ExpUp, gcMI); increaseSkillExp(pCastSlayer, DomainType, pSkillSlot, pSkillInfo, gcMI); pCastSlayer->getPlayer()->sendPacket(&gcMI); } } //cout << "EffectCureCriticalWounds " << "affect BEGIN" << endl; setNextTime(m_Delay); //cout << "EffectCureCriticalWounds " << "affect END" << endl; __END_CATCH }
void SwordOfThor::execute(Slayer * pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY // cout << "(x,y)=" << X << "," << Y << endl; Zone* pZone = pSlayer->getZone(); Assert(pZone!=NULL); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_SWORD; param.STRMultiplier = 8; param.DEXMultiplier = 1; param.INTMultiplier = 1; param.bMagicHitRoll = false; param.bMagicDamage = false; param.bAdd = false; param.bExpForTotalDamage = false; for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { param.addMask(i, j, 100); } SIMPLE_SKILL_OUTPUT result; // 목표위치+4방향 /* param.addMask(0 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100);*/ g_SimpleTileMissileSkill.execute(pSlayer, X, Y, pSkillSlot, param, result); if (result.bSuccess ) { for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { ZoneCoord_t tx = X+i; ZoneCoord_t ty = Y+j; if (!isValidZoneCoord(pZone, tx, ty) ) continue; Tile& rTile = pZone->getTile(tx, ty); if (!rTile.canAddEffect() ) continue; EffectSwordOfThor* pEffect = new EffectSwordOfThor(pZone, tx, ty); pEffect->setLevel(input.SkillLevel); pEffect->setDeadline(output.Duration); pZone->registerObject(pEffect); if (i != 0 || j != 0 ) pEffect->setBroadcastingEffect(false); else { GCAddEffectToTile gcAE; gcAE.setEffectID(pEffect->getSendEffectClass()); gcAE.setXY(tx, ty); gcAE.setObjectID(pEffect->getObjectID()); gcAE.setDuration(output.Duration); pZone->broadcastPacket(tx, ty, &gcAE); // cout << tx << ", " << ty << " Effect broadcast" << endl; } pZone->addEffect(pEffect); rTile.addEffect(pEffect); // cout << tx << ", " << ty << " add Effect" << endl; } } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 모터 사이클을 처리한다. ////////////////////////////////////////////////////////////////////////////// void CGRequestRepairHandler::executeMotorcycle (CGRequestRepair* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // 패킷 정보를 뽑아낸다. ObjectID_t ITEMOID = pPacket->getObjectID(); Creature* pPC = dynamic_cast<GamePlayer*>(pPlayer)->getCreature(); Zone* pZone = pPC->getZone(); Gold_t playerMoney = 0; ZoneCoord_t CenterX = pPC->getX(); ZoneCoord_t CenterY = pPC->getY(); Item* pItem = NULL; bool bSlayer = false; bool bVampire = false; bool bOusters = false; GCNPCResponse response; // 플레이어가 슬레이어인지 뱀파이어인지 구분. if (pPC->isSlayer()) bSlayer = true; else if (pPC->isVampire()) bVampire = true; else if (pPC->isOusters()) bOusters = true; else throw ProtocolException("CGRequestRepairHandler::execute() : Unknown player creature!"); // 플레이어가 수리하려고 하는 아이템을 가지고 있는지 // 상위에서 검사를 하기 때문에, pItem이 널일리는 없다. if (bSlayer) { pItem = (dynamic_cast<Slayer*>(pPC))->findItemOID(ITEMOID); playerMoney = (dynamic_cast<Slayer*>(pPC))->getGold(); } else if (bVampire) { pItem = (dynamic_cast<Vampire*>(pPC))->findItemOID(ITEMOID); playerMoney = (dynamic_cast<Vampire*>(pPC))->getGold(); } else if (bOusters) { pItem = (dynamic_cast<Ousters*>(pPC))->findItemOID(ITEMOID); playerMoney = (dynamic_cast<Ousters*>(pPC))->getGold(); } // 주위 일정 범위를 검색해서, 모터 사이클이 있는지 확인한다. for (ZoneCoord_t zx=CenterX-5; zx<=CenterX+5; zx++) { for (ZoneCoord_t zy=CenterY-5; zy<=CenterY+5; zy++) { if (!isValidZoneCoord(pZone, zx, zy)) continue; Tile & tile = pZone->getTile(zx, zy); if (tile.hasItem()) { Item* pItemOnTile = tile.getItem(); Assert(pItemOnTile != NULL); // 만일 아이템이 타일 위에 있을 경우, 모터 사이클인지 확인한다. if (pItemOnTile->getItemClass() == Item::ITEM_CLASS_MOTORCYCLE) { DWORD targetID = dynamic_cast<Key*>(pItem)->getTarget(); ItemID_t motorcycleID = pItemOnTile->getItemID(); if (targetID == motorcycleID) { Price_t repairPrice = g_pPriceManager->getRepairPrice(pItemOnTile); if (repairPrice > playerMoney) { response.setCode(NPC_RESPONSE_REPAIR_FAIL_MONEY); pPlayer->sendPacket(&response); return; } // 수리한다. repairItem(pItemOnTile); // 저장한다. //pItemOnTile->save(pPC->getName(), STORAGE_ZONE, pZone->getZoneID(), zx, zy); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Durability=%d", pItemOnTile->getDurability()); pItemOnTile->tinysave(pField); // 돈을 줄인다. //if (bSlayer) (dynamic_cast<Slayer*>(pPC))->setGoldEx(playerMoney-repairPrice); //else (dynamic_cast<Vampire*>(pPC))->setGoldEx(playerMoney-repairPrice); // by sigi. 2002.9.4 (dynamic_cast<PlayerCreature*>(pPC))->decreaseGoldEx(repairPrice); response.setCode(NPC_RESPONSE_REPAIR_OK); response.setParameter(playerMoney-repairPrice); pPlayer->sendPacket(&response); return; } // if (targetID == } // if (itemclas == MOTORCYCLE } } // end of for (ZoneCoord_t zy=CenterY-5; zy<=CenterY+5; zy++) } // end of for (ZoneCoord_t zx=CenterX-5; zx<=CenterX+5; zx++) // FOR 루프를 다 돌고, 이까지 왔다는 것은 근처에 오토바이가 없다는 말이당... // 그러므로 모터 사이클 팔기가 실패했다는 것을 알린다. response.setCode(NPC_RESPONSE_REPAIR_FAIL_ITEM_NOT_EXIST); pPlayer->sendPacket(&response); #endif __END_DEBUG_EX __END_CATCH }