void CParty::HealParty() { // XXX DELETEME 클라이언트 완료될때까지 { return; } if (!m_bPartyHealReady) return; TMemberMap::iterator it; LPCHARACTER l = GetLeaderCharacter(); for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) { if (!it->second.pCharacter) continue; LPCHARACTER ch = it->second.pCharacter; if (DISTANCE_APPROX(l->GetX()-ch->GetX(), l->GetY()-ch->GetY()) < PARTY_DEFAULT_RANGE) { ch->PointChange(POINT_HP, ch->GetMaxHP()-ch->GetHP()); ch->PointChange(POINT_SP, ch->GetMaxSP()-ch->GetSP()); } } m_bPartyHealReady = false; m_dwPartyHealTime = get_dword_time(); }
bool battle_distance_valid_by_xy(long x, long y, long tx, long ty) { long distance = DISTANCE_APPROX(x - tx, y - ty); if (distance > 170) return false; return true; }
bool CParty::IsPositionNearLeader(LPCHARACTER ch) { if (!m_pkChrLeader) return false; if (DISTANCE_APPROX(ch->GetX() - m_pkChrLeader->GetX(), ch->GetY() - m_pkChrLeader->GetY()) >= PARTY_DEFAULT_RANGE) return false; return true; }
bool CItem::DistanceValid(LPCHARACTER ch) { if (!GetSectree()) return false; int iDist = DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY()); if (iDist > 300) return false; return true; }
// 아이템 구입 void CShopManager::Buy(LPCHARACTER ch, BYTE pos) { if (!ch->GetShop()) return; if (!ch->GetShopOwner()) return; if (DISTANCE_APPROX(ch->GetX() - ch->GetShopOwner()->GetX(), ch->GetY() - ch->GetShopOwner()->GetY()) > 2000) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상점과의 거리가 너무 멀어 물건을 살 수 없습니다.")); return; } CShop* pkShop = ch->GetShop(); if (!pkShop->IsPCShop()) { //if (pkShop->GetVnum() == 0) // return; //const CMob* pkMob = CMobManager::instance().Get(pkShop->GetNPCVnum()); //if (!pkMob) // return; //if (pkMob->m_table.bType != CHAR_TYPE_NPC) //{ // return; //} } else { } //PREVENT_ITEM_COPY ch->SetMyShopTime(); //END_PREVENT_ITEM_COPY int ret = pkShop->Buy(ch, pos); if (SHOP_SUBHEADER_GC_OK != ret) // 문제가 있었으면 보낸다. { TPacketGCShop pack; pack.header = HEADER_GC_SHOP; pack.subheader = ret; pack.size = sizeof(TPacketGCShop); ch->GetDesc()->Packet(&pack, sizeof(pack)); } }
// 상점 거래를 시작 bool CShopManager::StartShopping(LPCHARACTER pkChr, LPCHARACTER pkChrShopKeeper, int iShopVnum) { if (pkChr->GetShopOwner() == pkChrShopKeeper) return false; // this method is only for NPC if (pkChrShopKeeper->IsPC()) return false; //PREVENT_TRADE_WINDOW if (pkChr->IsOpenSafebox() || pkChr->GetExchange() || pkChr->GetMyShop() || pkChr->IsCubeOpen()) { pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래창이 열린상태에서는 상점거래를 할수 가 없습니다.")); return false; } //END_PREVENT_TRADE_WINDOW long distance = DISTANCE_APPROX(pkChr->GetX() - pkChrShopKeeper->GetX(), pkChr->GetY() - pkChrShopKeeper->GetY()); if (distance >= SHOP_MAX_DISTANCE) { sys_log(1, "SHOP: TOO_FAR: %s distance %d", pkChr->GetName(), distance); return false; } LPSHOP pkShop; if (iShopVnum) pkShop = Get(iShopVnum); else pkShop = GetByNPCVnum(pkChrShopKeeper->GetRaceNum()); if (!pkShop) { sys_log(1, "SHOP: NO SHOP"); return false; } bool bOtherEmpire = false; if (pkChr->GetEmpire() != pkChrShopKeeper->GetEmpire()) bOtherEmpire = true; pkShop->AddGuest(pkChr, pkChrShopKeeper->GetVID(), bOtherEmpire); pkChr->SetShopOwner(pkChrShopKeeper); sys_log(0, "SHOP: START: %s", pkChr->GetName()); return true; }
void operator () (LPENTITY ent) { // 오브젝트가 아닌 것은 거리를 계산하여 거리가 멀면 추가하지 않는다. if (!ent->IsType(ENTITY_OBJECT)) if (DISTANCE_APPROX(ent->GetX() - m_me->GetX(), ent->GetY() - m_me->GetY()) > dwViewRange) return; // 나를 대상에 추가 m_me->ViewInsert(ent); // 둘다 캐릭터면 if (ent->IsType(ENTITY_CHARACTER) && m_me->IsType(ENTITY_CHARACTER)) { LPCHARACTER chMe = (LPCHARACTER) m_me; LPCHARACTER chEnt = (LPCHARACTER) ent; // 대상이 NPC면 StateMachine을 킨다. if (chMe->IsPC() && !chEnt->IsPC() && !chEnt->IsWarp() && !chEnt->IsGoto()) chEnt->StartStateMachine(); } }
LPCHARACTER CParty::GetNextOwnership(LPCHARACTER ch, long x, long y) { if (m_itNextOwner == m_memberMap.end()) return ch; int size = m_memberMap.size(); while (size-- > 0) { LPCHARACTER pkMember = m_itNextOwner->second.pCharacter; if (pkMember && DISTANCE_APPROX(pkMember->GetX() - x, pkMember->GetY() - y) < 3000) { IncreaseOwnership(); return pkMember; } IncreaseOwnership(); } return ch; }
bool operator () (LPENTITY ent) { if (!ent->IsType(ENTITY_CHARACTER)) return false; LPCHARACTER pkChr = (LPCHARACTER) ent; if (pkChr->IsBuilding() && (pkChr->IsAffectFlag(AFF_BUILDING_CONSTRUCTION_SMALL) || pkChr->IsAffectFlag(AFF_BUILDING_CONSTRUCTION_LARGE) || pkChr->IsAffectFlag(AFF_BUILDING_UPGRADE))) { m_pkChrBuilding = pkChr; } if (pkChr->IsNPC()) { if ( !pkChr->IsMonster() || !m_pkChr->IsAttackMob() || m_pkChr->IsAggressive() ) return false; } if (pkChr->IsDead()) return false; if (pkChr->IsAffectFlag(AFF_EUNHYUNG) || pkChr->IsAffectFlag(AFF_INVISIBILITY) || pkChr->IsAffectFlag(AFF_REVIVE_INVISIBLE)) return false; if (pkChr->IsAffectFlag(AFF_TERROR) && m_pkChr->IsImmune(IMMUNE_TERROR) == false ) // 공포 처리 { if ( pkChr->GetLevel() >= m_pkChr->GetLevel() ) return false; } if ( m_pkChr->IsNoAttackShinsu() ) { if ( pkChr->GetEmpire() == 1 ) return false; } if ( m_pkChr->IsNoAttackChunjo() ) { if ( pkChr->GetEmpire() == 2 ) return false; } if ( m_pkChr->IsNoAttackJinno() ) { if ( pkChr->GetEmpire() == 3 ) return false; } int iDistance = DISTANCE_APPROX(m_lx - pkChr->GetX(), m_ly - pkChr->GetY()); if (iDistance < m_iMinDistance && iDistance <= m_iMaxDistance) { m_pkChrVictim = pkChr; m_iMinDistance = iDistance; } return true; }
void CParty::Update() { sys_log(1, "PARTY::Update"); LPCHARACTER l = GetLeaderCharacter(); if (!l) return; TMemberMap::iterator it; int iNearMember = 0; bool bResendAll = false; for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) { LPCHARACTER ch = it->second.pCharacter; it->second.bNear = false; if (!ch) continue; if (l->GetDungeon()) it->second.bNear = l->GetDungeon() == ch->GetDungeon(); else it->second.bNear = (DISTANCE_APPROX(l->GetX()-ch->GetX(), l->GetY()-ch->GetY()) < PARTY_DEFAULT_RANGE); if (it->second.bNear) { ++iNearMember; //sys_log(0,"NEAR %s", ch->GetName()); } } if (iNearMember <= 1 && !l->GetDungeon()) { for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) it->second.bNear = false; iNearMember = 0; } if (iNearMember != m_iCountNearPartyMember) { m_iCountNearPartyMember = iNearMember; bResendAll = true; } m_iLeadership = l->GetLeadershipSkillLevel(); int iNewExpBonus = ComputePartyBonusExpPercent(); m_iAttBonus = ComputePartyBonusAttackGrade(); m_iDefBonus = ComputePartyBonusDefenseGrade(); if (m_iExpBonus != iNewExpBonus) { bResendAll = true; m_iExpBonus = iNewExpBonus; } bool bLongTimeExpBonusChanged = false; // 파티 결성 후 충분한 시간이 지나면 경험치 보너스를 받는다. if (!m_iLongTimeExpBonus && (get_dword_time() - m_dwPartyStartTime > PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS * 60 * 1000 / (g_iUseLocale?1:2))) { bLongTimeExpBonusChanged = true; m_iLongTimeExpBonus = 5; bResendAll = true; } for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) { LPCHARACTER ch = it->second.pCharacter; if (!ch) continue; if (bLongTimeExpBonusChanged && ch->GetDesc()) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("파티의 협동력이 높아져 지금부터 추가 경험치 보너스를 받습니다.")); bool bNear = it->second.bNear; ComputeRolePoint(ch, it->second.bRole, bNear); if (bNear) { if (!bResendAll) SendPartyInfoOneToAll(ch); } } // PARTY_ROLE_LIMIT_LEVEL_BUG_FIX m_anMaxRole[PARTY_ROLE_ATTACKER] = m_iLeadership >= 10 ? 1 : 0; m_anMaxRole[PARTY_ROLE_HASTE] = m_iLeadership >= 20 ? 1 : 0; m_anMaxRole[PARTY_ROLE_TANKER] = m_iLeadership >= 20 ? 1 : 0; m_anMaxRole[PARTY_ROLE_BUFFER] = m_iLeadership >= 25 ? 1 : 0; m_anMaxRole[PARTY_ROLE_SKILL_MASTER] = m_iLeadership >= 35 ? 1 : 0; m_anMaxRole[PARTY_ROLE_DEFENDER] = m_iLeadership >= 40 ? 1 : 0; m_anMaxRole[PARTY_ROLE_ATTACKER] += m_iLeadership >= 40 ? 1 : 0; // END_OF_PARTY_ROLE_LIMIT_LEVEL_BUG_FIX // Party Heal Update if (!m_bPartyHealReady) { if (!m_bCanUsePartyHeal && m_iLeadership >= 18) m_dwPartyHealTime = get_dword_time(); m_bCanUsePartyHeal = m_iLeadership >= 18; // 통솔력 18 이상은 힐을 사용할 수 있음. // 통솔력 40이상은 파티 힐 쿨타임이 적다. DWORD PartyHealCoolTime = (m_iLeadership >= 40) ? PARTY_HEAL_COOLTIME_SHORT * 60 * 1000 : PARTY_HEAL_COOLTIME_LONG * 60 * 1000; if (m_bCanUsePartyHeal) { if (get_dword_time() > m_dwPartyHealTime + PartyHealCoolTime) { m_bPartyHealReady = true; // send heal ready if (0) // XXX DELETEME 클라이언트 완료될때까지 if (GetLeaderCharacter()) GetLeaderCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "PartyHealReady"); } } } if (bResendAll) { for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it) if (it->second.pCharacter) SendPartyInfoOneToAll(it->second.pCharacter); } }
int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim) { if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); if (!victim || ch == victim) return BATTLE_NONE; if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); if (!battle_is_attackable(ch, victim)) return BATTLE_NONE; if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); // 거리 체크 int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY()); if (!victim->IsBuilding()) { int max = 300; if (false == ch->IsPC()) { // 몬스터의 경우 몬스터 공격 거리를 사용 max = (int) (ch->GetMobAttackRange() * 1.15f); } else { // PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리 if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType()) max = MAX(300, (int) (victim->GetMobAttackRange() * 1.15f)); } if (distance > max) { if (test_server) sys_log(0, "VICTIM_FAR: %s distance: %d max: %d", ch->GetName(), distance, max); return BATTLE_NONE; } } if (timed_event_cancel(ch)) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다.")); if (timed_event_cancel(victim)) victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다.")); ch->SetPosition(POS_FIGHTING); ch->SetVictim(victim); const PIXEL_POSITION & vpos = victim->GetXYZ(); ch->SetRotationToXY(vpos.x, vpos.y); int dam; int ret = battle_hit(ch, victim, dam); return (ret); }
void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount) { if (!ch->GetShop()) return; if (!ch->GetShopOwner()) return; if (!ch->CanHandleItem()) return; if (ch->GetShop()->IsPCShop()) return; if (DISTANCE_APPROX(ch->GetX()-ch->GetShopOwner()->GetX(), ch->GetY()-ch->GetShopOwner()->GetY())>2000) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상점과의 거리가 너무 멀어 물건을 팔 수 없습니다.")); return; } LPITEM item = ch->GetInventoryItem(bCell); if (!item) return; if (item->IsEquipped() == true) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("착용 중인 아이템은 판매할 수 없습니다.")); return; } if (true == item->isLocked()) { return; } if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_SELL)) return; DWORD dwPrice; if (bCount == 0 || bCount > item->GetCount()) bCount = item->GetCount(); dwPrice = item->GetShopBuyPrice(); if (IS_SET(item->GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD)) { if (dwPrice == 0) dwPrice = bCount; else dwPrice = bCount / dwPrice; } else dwPrice *= bCount; dwPrice /= 5; //세금 계산 DWORD dwTax = 0; int iVal = 3; if (LC_IsYMIR() || LC_IsKorea()) { dwTax = dwPrice * iVal / 100; dwPrice -= dwTax; } else { dwTax = dwPrice * iVal/100; dwPrice -= dwTax; } if (test_server) sys_log(0, "Sell Item price id %d %s itemid %d", ch->GetPlayerID(), ch->GetName(), item->GetID()); const int64_t nTotalMoney = static_cast<int64_t>(ch->GetGold()) + static_cast<int64_t>(dwPrice); if (GOLD_MAX <= nTotalMoney) { sys_err("[OVERFLOW_GOLD] id %u name %s gold %u", ch->GetPlayerID(), ch->GetName(), ch->GetGold()); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20억냥이 초과하여 물품을 팔수 없습니다.")); return; } // 20050802.myevan.상점 판매 로그에 아이템 ID 추가 sys_log(0, "SHOP: SELL: %s item name: %s(x%d):%u price: %u", ch->GetName(), item->GetName(), bCount, item->GetID(), dwPrice); if (iVal > 0) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("판매금액의 %d %% 가 세금으로 나가게됩니다"), iVal); DBManager::instance().SendMoneyLog(MONEY_LOG_SHOP, item->GetVnum(), dwPrice); if (bCount == item->GetCount()) { // 한국에는 아이템을 버리고 복구해달라는 진상유저들이 많아서 // 상점 판매시 속성로그를 남긴다. if (LC_IsYMIR()) item->AttrLog(); ITEM_MANAGER::instance().RemoveItem(item, "SELL"); } else item->SetCount(item->GetCount() - bCount); //군주 시스템 : 세금 징수 CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch); ch->PointChange(POINT_GOLD, dwPrice, false); }
void CParty::Update() { sys_log(1, "PARTY::Update"); LPCHARACTER l = GetLeaderCharacter(); if (!l) return; TMemberMap::iterator it; int iNearMember = 0; bool bResendAll = false; for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) { LPCHARACTER ch = it->second.pCharacter; it->second.bNear = false; if (!ch) continue; if (l->GetDungeon()) it->second.bNear = l->GetDungeon() == ch->GetDungeon(); else it->second.bNear = (DISTANCE_APPROX(l->GetX()-ch->GetX(), l->GetY()-ch->GetY()) < PARTY_DEFAULT_RANGE); if (it->second.bNear) { ++iNearMember; //sys_log(0,"NEAR %s", ch->GetName()); } } if (iNearMember <= 1 && !l->GetDungeon()) { for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) it->second.bNear = false; iNearMember = 0; } if (iNearMember != m_iCountNearPartyMember) { m_iCountNearPartyMember = iNearMember; bResendAll = true; } m_iLeadership = l->GetLeadershipSkillLevel(); int iNewExpBonus = ComputePartyBonusExpPercent(); m_iAttBonus = ComputePartyBonusAttackGrade(); m_iDefBonus = ComputePartyBonusDefenseGrade(); if (m_iExpBonus != iNewExpBonus) { bResendAll = true; m_iExpBonus = iNewExpBonus; } bool bLongTimeExpBonusChanged = false; // ЖДЖј °бјє ИД ГжєРЗС ЅГ°ЈАМ БціЄёй °жЗиДЎ єёіКЅєё¦ №ЮґВґЩ. if (!m_iLongTimeExpBonus && (get_dword_time() - m_dwPartyStartTime > PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS * 60 * 1000 / (g_iUseLocale?1:2))) { bLongTimeExpBonusChanged = true; m_iLongTimeExpBonus = 5; bResendAll = true; } for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) { LPCHARACTER ch = it->second.pCharacter; if (!ch) continue; if (bLongTimeExpBonusChanged && ch->GetDesc()) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ЖДЖјАЗ Зщµї·ВАМ іфѕЖБ® Бц±ЭєОЕН ГЯ°Ў °жЗиДЎ єёіКЅєё¦ №ЮЅАґПґЩ.")); bool bNear = it->second.bNear; ComputeRolePoint(ch, it->second.bRole, bNear); if (bNear) { if (!bResendAll) SendPartyInfoOneToAll(ch); } } // PARTY_ROLE_LIMIT_LEVEL_BUG_FIX m_anMaxRole[PARTY_ROLE_ATTACKER] = m_iLeadership >= 10 ? 1 : 0; m_anMaxRole[PARTY_ROLE_HASTE] = m_iLeadership >= 20 ? 1 : 0; m_anMaxRole[PARTY_ROLE_TANKER] = m_iLeadership >= 20 ? 1 : 0; m_anMaxRole[PARTY_ROLE_BUFFER] = m_iLeadership >= 25 ? 1 : 0; m_anMaxRole[PARTY_ROLE_SKILL_MASTER] = m_iLeadership >= 35 ? 1 : 0; m_anMaxRole[PARTY_ROLE_DEFENDER] = m_iLeadership >= 40 ? 1 : 0; m_anMaxRole[PARTY_ROLE_ATTACKER] += m_iLeadership >= 40 ? 1 : 0; // END_OF_PARTY_ROLE_LIMIT_LEVEL_BUG_FIX // Party Heal Update if (!m_bPartyHealReady) { if (!m_bCanUsePartyHeal && m_iLeadership >= 18) m_dwPartyHealTime = get_dword_time(); m_bCanUsePartyHeal = m_iLeadership >= 18; // ЕлјЦ·В 18 АМ»уАє ИъА» »зїлЗТ јц АЦАЅ. // ЕлјЦ·В 40АМ»уАє ЖДЖј Иъ ДрЕёАУАМ АыґЩ. DWORD PartyHealCoolTime = (m_iLeadership >= 40) ? PARTY_HEAL_COOLTIME_SHORT * 60 * 1000 : PARTY_HEAL_COOLTIME_LONG * 60 * 1000; if (m_bCanUsePartyHeal) { if (get_dword_time() > m_dwPartyHealTime + PartyHealCoolTime) { m_bPartyHealReady = true; // send heal ready if (0) // XXX DELETEME Е¬¶уАМѕрЖ® їП·бµЙ¶§±оБц if (GetLeaderCharacter()) GetLeaderCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "PartyHealReady"); } } } if (bResendAll) { for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it) if (it->second.pCharacter) SendPartyInfoOneToAll(it->second.pCharacter); } }
int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim) { if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); if (!victim || ch == victim) return BATTLE_NONE; if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); if (!battle_is_attackable(ch, victim)) return BATTLE_NONE; if (test_server&&ch->IsPC()) sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName()); // °Её® ГјЕ© int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY()); if (!victim->IsBuilding()) { int max = 300; if (false == ch->IsPC()) { // ёуЅєЕНАЗ °жїм ёуЅєЕН °ш°Э °Её®ё¦ »зїл max = (int) (ch->GetMobAttackRange() * 1.15f); } else { // PCАП °жїм »уґл°Ў melee ёчАП °жїм ёчАЗ °ш°Э °Её®°Ў ГЦґл °ш°Э °Её® if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType()) max = MAX(300, (int) (victim->GetMobAttackRange() * 1.15f)); } if (distance > max) { if (test_server) sys_log(0, "VICTIM_FAR: %s distance: %d max: %d", ch->GetName(), distance, max); return BATTLE_NONE; } } if (timed_event_cancel(ch)) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("АьЕх°Ў ЅГАЫ µЗѕо ГлјТ µЗѕъЅАґПґЩ.")); if (timed_event_cancel(victim)) victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("АьЕх°Ў ЅГАЫ µЗѕо ГлјТ µЗѕъЅАґПґЩ.")); ch->SetPosition(POS_FIGHTING); ch->SetVictim(victim); const PIXEL_POSITION & vpos = victim->GetXYZ(); ch->SetRotationToXY(vpos.x, vpos.y); int dam; int ret = battle_hit(ch, victim, dam); return (ret); }