Jump to content

msnas

Premium
  • Posts

    44
  • Joined

  • Days Won

    1
  • Feedback

    0%

msnas last won the day on July 27 2017

msnas had the most liked content!

5 Followers

About msnas

Informations

  • Gender
    Male

Recent Profile Visitors

2825 profile views

msnas's Achievements

Proficient

Proficient (10/16)

  • Very Popular Rare
  • Reacting Well
  • Dedicated
  • First Post
  • Collaborator

Recent Badges

1.3k

Reputation

  1. That's definitely going to crash the server. @ Rakancito, can you explain how you thought process of this code?
  2. I would also love to add Azure Dev Ops to the mix - It has an amazing board, every US (card) has a number, unlimited storage for you repo but the best part is to be fully connected through Visual Studio. It's the one I currently use for local systems and testing: Ah, and it's completely free (máx 5 users, then it's 5€/m per extra user).
  3. PIXEL_POSITION pxPos = GetXYZ(); LPITEM item; for (int i = 0; i < WEAR_MAX_NUM; ++i) { if ((item = GetWear(i))) { item->RemoveFromCharacter(); item->AddToGround(GetMapIndex(), pxPos); item->StartDestroyEvent(); LogManager::instance().ItemLog(this, item, "DROP_EVENT", item->GetName()); } }
  4. PIXEL_POSITION pxPos = GetXYZ(); LPITEM item; for (int i = 0; i < WEAR_MAX_NUM; ++i) { if ((item = GetWear(i))) { item->RemoveFromCharacter(); item->AddToGround(GetMapIndex(), pxPos); item->StartDestroyEvent(); LogManager::instance().ItemLog(this, item, "DROP_EVENT", item->GetID()); } }
  5. [Hidden Content] [Hidden Content] Change Your Equipment! This update allows you to unlock a second equipment page and switch quickly and easily between two loadouts! No longer will you have to change each piece of equipment individually when you want to don a different set. Instead you can enjoy a super-speedy equipment change at the touch of a button. For example, you can clad yourself in PvP equipment on one page and PvE equipment on the other, so you’re perfectly prepared for anything! How It Works To unlock the second equipment page you’ll need the new Extra Equipment Page item. Use the item and the second equipment page will appear. You can kit this out just as you did the first one. As soon as you’ve activated the additional equipment page, the associated Change Equipment Page skill will automatically be unlocked so you can change equipment quickly and easily at any time. You’ll find this skill in your secondary skills.
  6. PIXEL_POSITION pxPos = GetXYZ(); LPITEM item; for (int i = 0; i < WEAR_MAX_NUM; ++i) { if ((item = ch->GetWear(i))) { item->RemoveFromCharacter(); item->AddToGround(GetMapIndex(), pxPos); item->StartDestroyEvent(); LogManager::instance().ItemLog(this, item, "DROP_EVENT", item->GetID()); } } It's possible but it would require time.
  7. Download Alternative download links → Github [Hidden Content] A couple of days ago, I was searching something on metin2 wiki and found out there's a new called Shoulder Sash Transfer . After talking to some people who play the official version, I realised it wasn't being used. Some didn't even know of the item's existence. There's @ Mali's version but I didn't know he had done it + doesn't have the sash/acce transfer. Nonetheless, I decided to create the code for the full Item Combination (this means Costume Bonus Transfer is also included). Costume Bonus Transfer is straightforward, you transfer bonus from a costume to another. Here are the requirements in order to get the bonus transfered: Costume's source need to have bonus If costume's target has bonus, it will be removed Both costumes need to have the same type and subtyp (eg: You can't transfer bonus from a costume head to a costume body) Shoulder Sash Transfer is more tricky, has 3 levels: Total success: Your sash will absorb all bonus without any penalization Partial success: Your sash will absorb all bonus BUT the absorption rate will decrease 1% (25% -> 24%). That means all bonus will be recalculated according to the new absorption rate. Failure: Your sash WON'T absorb bonus BUT you won't lose the sash you're using to transfer all bonus. Here are the requirements in order to get the bonus transfered: You cannot use a sash with a bonus for the target You cannot use a sash without a bonus as the source You cannot transfer the bonus as the sashes have different grades You cannot transfer the bonus as the sashes have different absorption rates I tried to be as official-like as possible, there are one or other func missing but everything is working just fine. Thanks to @ Gurgarath for helping me understand the partial success stuff!
  8. I understand the objective of checking but m_pTopWindow is considered NULL by default. Meaning the code wouldn't work without wndMgr.SetWheelTopWindow There's no reason to use that piece of code.
  9. I found something interesting. The tool is only checking if Pi_InitModule starts as a PyObject's variable. However, there are some files that aren't being initialized in that way - 14 to be exact: The solution would be to remove/comment this line: And voilá, files like PythonDebugModule.cpp are being called correctly:
  10. // cmd_general.cpp case POINT_ITEM_DROP_BONUS: return LC_TEXT("%d%% 확률로 적퇴치시 아이템 2배 드롭"); // constants.cpp { POINT_ITEM_DROP_BONUS, }, // APPLY_ITEM_DROP_BONUS, 45 // char.cpp case POINT_ITEM_DROP_BONUS: // 73 if (GetPoint(type) + amount > 100) { sys_err("BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount); amount = 100 - GetPoint(type); } SetPoint(type, GetPoint(type) + amount); val = GetPoint(type); break; // char.h POINT_ITEM_DROP_BONUS, // 85 Taken from the original source, this are all the referenced points. void CHARACTER::Reward(bool bItemDrop) { if (GetRaceNum() == 5001) // їЦ±ёґВ µ·А» №«Б¶°З µе·У { PIXEL_POSITION pos; if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos)) return; LPITEM item; int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax); iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100; iGold *= GetGoldMultipler(); int iSplitCount = number(25, 35); sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount); for (int i = 1; i <= iSplitCount; ++i) { if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount))) { if (i != 0) { pos.x = number(-7, 7) * 20; pos.y = number(-7, 7) * 20; pos.x += GetX(); pos.y += GetY(); } item->AddToGround(GetMapIndex(), pos); item->StartDestroyEvent(); } } return; } //PROF_UNIT puReward("Reward"); LPCHARACTER pkAttacker = DistributeExp(); if (!pkAttacker) return; //PROF_UNIT pu1("r1"); if (pkAttacker->IsPC()) { if (GetLevel() - pkAttacker->GetLevel() >= -10) if (pkAttacker->GetRealAlignment() < 0) { if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL)) pkAttacker->UpdateAlignment(14); else pkAttacker->UpdateAlignment(7); } else pkAttacker->UpdateAlignment(2); pkAttacker->SetQuestNPCID(GetVID()); quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum()); CHARACTER_MANAGER::instance().KillLog(GetRaceNum()); if (!number(0, 9)) { if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY)) { int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100; pkAttacker->PointChange(POINT_HP, iHP); CreateFly(FLY_HP_SMALL, pkAttacker); } if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER)) { int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100; pkAttacker->PointChange(POINT_SP, iSP); CreateFly(FLY_SP_SMALL, pkAttacker); } } } //pu1.Pop(); if (!bItemDrop) return; PIXEL_POSITION pos = GetXYZ(); if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos)) return; // // µ· µе·У // //PROF_UNIT pu2("r2"); if (test_server) sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName()); RewardGold(pkAttacker); //pu2.Pop(); // // ѕЖАМЕЫ µе·У // //PROF_UNIT pu3("r3"); LPITEM item; static std::vector<LPITEM> s_vec_item; s_vec_item.clear(); if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item)) { if (s_vec_item.size() == 0); else if (s_vec_item.size() == 1) { item = s_vec_item[0]; item->AddToGround(GetMapIndex(), pos); if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false) { item->SetOwnership(pkAttacker); } item->StartDestroyEvent(); pos.x = number(-7, 7) * 20; pos.y = number(-7, 7) * 20; pos.x += GetX(); pos.y += GetY(); sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName()); } else { int iItemIdx = s_vec_item.size() - 1; std::priority_queue<std::pair<int, LPCHARACTER> > pq; int total_dam = 0; for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it) { int iDamage = it->second.iTotalDamage; if (iDamage > 0) { LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first); if (ch) { pq.push(std::make_pair(iDamage, ch)); total_dam += iDamage; } } } std::vector<LPCHARACTER> v; while (!pq.empty() && pq.top().first * 10 >= total_dam) { v.push_back(pq.top().second); pq.pop(); } if (v.empty()) { // µҐ№МБцё¦ ЖЇє°Ич ё№АМ БШ »з¶чАМ ѕшАёґП јТАЇ±З ѕшАЅ while (iItemIdx >= 0) { item = s_vec_item[iItemIdx--]; if (!item) { sys_err("item null in vector idx %d", iItemIdx + 1); continue; } item->AddToGround(GetMapIndex(), pos); // 10% АМЗП µҐ№МБц БШ »з¶чіўё®ґВ јТАЇ±ЗѕшАЅ //item->SetOwnership(pkAttacker); item->StartDestroyEvent(); pos.x = number(-7, 7) * 20; pos.y = number(-7, 7) * 20; pos.x += GetX(); pos.y += GetY(); sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName()); } } else { // µҐ№МБц ё№АМ БШ »з¶чµй іўё®ёё јТАЇ±З іЄґІ°ЎБь std::vector<LPCHARACTER>::iterator it = v.begin(); while (iItemIdx >= 0) { item = s_vec_item[iItemIdx--]; if (!item) { sys_err("item null in vector idx %d", iItemIdx + 1); continue; } item->AddToGround(GetMapIndex(), pos); LPCHARACTER ch = *it; if (ch->GetParty()) ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY()); ++it; if (it == v.end()) it = v.begin(); if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false) { item->SetOwnership(ch); } item->StartDestroyEvent(); pos.x = number(-7, 7) * 20; pos.y = number(-7, 7) * 20; pos.x += GetX(); pos.y += GetY(); sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName()); } } } } m_map_kDamage.clear(); } Default Reward function. The only thing that actually adds some kind of calculation is ITEM_MANAGER::GetDropPct: bool ITEM_MANAGER::GetDropPct(LPCHARACTER pkChr, LPCHARACTER pkKiller, OUT int& iDeltaPercent, OUT int& iRandRange) { if (NULL == pkChr || NULL == pkKiller) return false; ..... iRandRange = 4000000; iRandRange = iRandRange * 100 / (100 + CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) + pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM)?100:0); if (distribution_test_server) iRandRange /= 3; return true; } // And the UNIQUE_ITEM_DOUBLE_ITEM is Thief's Gloves. Please tell me where is the calculation for the Chance to drop double the Items/POINT_ITEM_DROP_BONUS. Don't use your arguments by saying "it works on the official ones, so you're wrong", prove us wrong by using facts.
  11. Yes, you can have it that way, I was explaining why you shouldn't need to worry about that since the function won't be called in a default way.
  12. You're trying to call a function that it doesn't exist. Check the tutorial for ItemManager.h and ItemManager.cpp
  13. Yes, the problem is there and your logical is correct. However, it shouldn't be an issue. Shal we trace a little bit? // PythonNetworkPhaseLoading.cpp HEADER_GC_MAIN_CHARACTER // Header calling the function bool CPythonNetworkStream::RecvMainCharacter() // Function // input_db.cpp void CInputDB::PlayerLoad(LPDESC d, const char * data) { .... ch->MainCharacterPacket(); // Calling the function } // char.cpp void CHARACTER::MainCharacterPacket() { const unsigned mapIndex = GetMapIndex(); const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex); // SUPPORT_BGM if (!bgmInfo.name.empty()) { if (CHARACTER_IsBGMVolumeEnable()) { sys_log(1, "bgm_info.play_bgm_vol(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), bgmInfo.vol); TPacketGCMainCharacter4_BGM_VOL mainChrPacket; mainChrPacket.header = HEADER_GC_MAIN_CHARACTER4_BGM_VOL; mainChrPacket.dwVID = m_vid; mainChrPacket.wRaceNum = GetRaceNum(); mainChrPacket.lx = GetX(); mainChrPacket.ly = GetY(); mainChrPacket.lz = GetZ(); mainChrPacket.empire = GetDesc()->GetEmpire(); mainChrPacket.skill_group = GetSkillGroup(); strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName)); mainChrPacket.fBGMVol = bgmInfo.vol; strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName)); GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter4_BGM_VOL)); } else { sys_log(1, "bgm_info.play(%d, '%s')", mapIndex, bgmInfo.name.c_str()); TPacketGCMainCharacter3_BGM mainChrPacket; mainChrPacket.header = HEADER_GC_MAIN_CHARACTER3_BGM; mainChrPacket.dwVID = m_vid; mainChrPacket.wRaceNum = GetRaceNum(); mainChrPacket.lx = GetX(); mainChrPacket.ly = GetY(); mainChrPacket.lz = GetZ(); mainChrPacket.empire = GetDesc()->GetEmpire(); mainChrPacket.skill_group = GetSkillGroup(); strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName)); strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName)); GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter3_BGM)); } //if (m_stMobile.length()) // ChatPacket(CHAT_TYPE_COMMAND, "sms"); } // END_OF_SUPPORT_BGM ..... } Let's understand first the functions: // Getting the current map index where the player is and find out if there is any music associated to the map const unsigned mapIndex = GetMapIndex(); const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex); .... if (CHARACTER_IsBGMVolumeEnable()) // Gets if the bgm volume is enable (we'll go through this later= .... } // A std::map that assigns a map to a music. typedef std::map<unsigned, BGMInfo> BGMInfoMap; // Sets gs_bgmVolEnable to true void CHARACTER_SetBGMVolumeEnable() { gs_bgmVolEnable = true; sys_log(0, "bgm_info.set_bgm_volume_enable"); } // Adds info to the std::map void CHARACTER_AddBGMInfo(unsigned mapIndex, const char* name, float vol) { BGMInfo newInfo; newInfo.name = name; newInfo.vol = vol; gs_bgmInfoMap[mapIndex] = newInfo; sys_log(0, "bgm_info.add_info(%d, '%s', %f)", mapIndex, name, vol); } // Gets the info in the std::map const BGMInfo& CHARACTER_GetBGMInfo(unsigned mapIndex) { BGMInfoMap::iterator f = gs_bgmInfoMap.find(mapIndex); if (gs_bgmInfoMap.end() == f) { static BGMInfo s_empty = {"", 0.0f}; return s_empty; } return f->second; } So far, we don't quite understand what's the problem, but let's try to trace even futher. void CHARACTER::MainCharacterPacket() { const unsigned mapIndex = GetMapIndex(); const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex); if (!bgmInfo.name.empty()) // If there is any music associated to the map { if (CHARACTER_IsBGMVolumeEnable()) // If the variable gs_bgmVolEnable is true // something happens else // If the gs_bgmVolEnable variable is false // other stuff happens } else // If there isn't any music associated to the map { sys_log(0, "bgm_info.play(%d, DEFAULT_BGM_NAME)", mapIndex); TPacketGCMainCharacter pack; pack.header = HEADER_GC_MAIN_CHARACTER; pack.dwVID = m_vid; pack.wRaceNum = GetRaceNum(); pack.lx = GetX(); pack.ly = GetY(); pack.lz = GetZ(); pack.empire = GetDesc()->GetEmpire(); pack.skill_group = GetSkillGroup(); strlcpy(pack.szName, GetName(), sizeof(pack.szName)); GetDesc()->Packet(&pack, sizeof(TPacketGCMainCharacter)); } } But why it shouldn't happen? Because, by default all the info is being called in settings.lua in your share folder. add_bgm_info( 1, "enter_the_east.mp3", 0.5); add_bgm_info(21, "enter_the_east.mp3", 0.5); add_bgm_info(41, "enter_the_east.mp3", 0.5); add_bgm_info( 3, "back_to_back.mp3", 0.5); add_bgm_info(23, "back_to_back.mp3", 0.5); add_bgm_info(43, "back_to_back.mp3", 0.5); add_bgm_info(63, "open_the_gate.mp3", 0.5); add_bgm_info(69, "open_the_gate.mp3", 0.5); add_bgm_info(70, "open_the_gate.mp3", 0.5); add_bgm_info(67, "a_rhapsody_of_war.mp3", 0.5); add_bgm_info(68, "lost_my_name.mp3", 0.5); add_bgm_info(65, "wonderland.mp3", 0.5); add_bgm_info(61, "mountain_of_death.mp3", 0.5); add_bgm_info(64, "save_me.mp3", 0.5); add_bgm_info(74, "mountain_of_death.mp3", 0.5); add_bgm_info(75, "follow_war_god.mp3", 0.5); add_bgm_info(76, "mountain_of_death.mp3", 0.5); add_bgm_info(77, "save_me.mp3", 0.5); add_bgm_info(78, "wonderland.mp3", 0.5); add_bgm_info(104, "Only_my_battle.mp3", 0.5); add_bgm_info(62, "follow_war_god.mp3", 0.5); add_bgm_info(66, "death_of_landmark.mp3", 0.5); add_bgm_info(107, "monkey_temple.mp3", 0.5); add_bgm_info(108, "monkey_temple.mp3", 0.5); add_bgm_info(109, "monkey_temple.mp3", 0.5); add_bgm_info(114, "last-war2.mp3", 0.5); add_bgm_info(115, "last-war2.mp3", 0.5); add_bgm_info(116, "last-war2.mp3", 0.5); add_bgm_info(117, "last-war2.mp3", 0.5); add_bgm_info(118, "last-war2.mp3", 0.5); add_bgm_info(119, "last-war2.mp3", 0.5); add_bgm_info(120, "last-war2.mp3", 0.5); add_bgm_info(121, "last-war2.mp3", 0.5); add_bgm_info(122, "last-war2.mp3", 0.5); add_bgm_info(123, "last-war2.mp3", 0.5); add_bgm_info(124, "last-war2.mp3", 0.5); add_bgm_info(125, "last-war2.mp3", 0.5); add_bgm_info(126, "last-war2.mp3", 0.5); add_bgm_info(127, "last-war2.mp3", 0.5); add_bgm_info(128, "last-war2.mp3", 0.5); add_bgm_info(181, "last-war2.mp3", 0.5); add_bgm_info(182, "last-war2.mp3", 0.5); add_bgm_info(183, "last-war2.mp3", 0.5); add_bgm_info(216, "catacomb_of_devil.mp3", 0.5); add_bgm_info(71, "Only_my_battle.mp3", 0.5); add_bgm_info(217, "Only_my_battle.mp3", 0.5); add_bgm_info(301, "another_way.mp3", 0.5); add_bgm_info(302, "misty_forest.mp3", 0.5); add_bgm_info(303, "blacksea.mp3", 0.5); add_bgm_info(304, "mt.mp3", 0.5); set_bgm_volume_enable(); int _set_bgm_volume_enable(lua_State* L) { CHARACTER_SetBGMVolumeEnable(); return 0; } int _add_bgm_info(lua_State* L) { if (!lua_isnumber(L, 1) || !lua_isstring(L, 2)) return 0; int mapIndex = (int)lua_tonumber(L, 1); const char* bgmName = lua_tostring(L, 2); if (!bgmName) return 0; float bgmVol = lua_isnumber(L, 3) ? lua_tonumber(L, 3) : (1.0f/5.0f)*0.1f; CHARACTER_AddBGMInfo(mapIndex, bgmName, bgmVol); return 0; } This is also being called everytime you enter the game. So, in theory you shouldn't worry about that, but it's a nice catch and you can change it. OBS: If there isn't any music associated to a map, it will use the default: M2BG.mp3 (inside BGM folder) TLDR: Yes, but no.
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.