Jump to content

msnas

Premium
  • Posts

    46
  • Joined

  • Days Won

    1
  • Feedback

    100%

msnas last won the day on July 27 2017

msnas had the most liked content!

About msnas

Informations

  • Gender
    Male

Recent Profile Visitors

4958 profile views

msnas's Achievements

Experienced

Experienced (11/16)

  • Well Followed Rare
  • Very Popular Rare
  • Reacting Well
  • Dedicated
  • Collaborator Rare

Recent Badges

2.3k

Reputation

  1. @ Gurgarath already gave you some useful tips. I just want to emphasize that having your project set up with CMake makes it significantly easier to maintain a unified structure for compiling both on Windows and FreeBSD (or even Linux, assuming compatibility). What I’d also recommend is setting up a pipeline that automatically compiles the server source whenever you push a commit to your repository. This pipeline should upload the updated files directly to the vm and compile them there. That way, you eliminate the need to manually transfer files back and forth. If your server vm and compile vm is the same, you can even automate stopping the server before the process begins and starting it again at the end, all triggered by a simple git push. As for the best repo structure in my opinion, 4 repositories are enough to have the pipelines working efficiently: Server Source Client Source Client Common (tool sources like dump_proto, world editor, etc) 2 pipelines, one for server and one for client (commit -> compile client source and push the binary to client repo) should do the trick.
  2. Following this message, enforcing on the server would be something like this: bool CHARACTER::Attack(LPCHARACTER pkVictim, uint8_t bType) { .... if (IsPC()) { if (IS_SPEED_HACK(this, pkVictim, dwCurrentTime)) return false; if (bType == 0 && dwCurrentTime < GetSkipComboAttackByTime()) return false; const uint16_t part_weapon = GetPart(PART_WEAPON); if (part_weapon >= 50201 && part_weapon <= 50204) return false; } }
  3. That's definitely going to crash the server. @ Rakancito, can you explain how you thought process of this code?
  4. 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).
  5. 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()); } }
  6. 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()); } }
  7. [Hidden Content] Open it with excel:
  8. [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.
  9. 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.
  10. 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!
  11. 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.
  12. 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:
  13. // 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.
  14. 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.
  15. You're trying to call a function that it doesn't exist. Check the tutorial for ItemManager.h and ItemManager.cpp
×
×
  • 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.