Jump to content

Braxy

Bronze
  • Posts

    182
  • Joined

  • Last visited

  • Days Won

    7
  • Feedback

    0%

Braxy last won the day on July 12 2019

Braxy had the most liked content!

3 Followers

About Braxy

  • Birthday 11/24/1999

Informations

  • Gender
    Male

Social Networks

  • Discord
    .braxy1

Recent Profile Visitors

3385 profile views

Braxy's Achievements

Proficient

Proficient (10/16)

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

Recent Badges

573

Reputation

  1. PointChange already checks for the maximum gold limit. What you did will eventually stop the loop and you will lose the other chest items. (you can get a crash as well by calling the deleted item) If you want to atleast give the gold they can receive upon their gold limit you can do it like this: case CSpecialItemGroup::GOLD: { if (llItemCount + GetGold() > GOLD_MAX) llItemCount = MIN(llItemCount, GOLD_MAX - GetGold()); PointChange(POINT_GOLD, llItemCount); ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have received %d Yang."), llItemCount); }
  2. (This topic addresses to the most common crashes that occur using server_timers in dungeons) In this short tutorial i'm gonna explain why are the crashes happening and how we can deal with them along with a use case of this. The difference between the Normal Timers and Server Timers Normal Timers: - Directly tied to a character pointer. - Timer execution halts if the associated character logs out. - Implicitly dependent on the character's in-game presence. Server Timers: - Operate independently of character pointers. - Continue to execute even if the initiating character exits the game. - Offers persistent timing functionalities. You might ponder on the need for server timers, especially when normal timers are present. Here's why: 1. Party Dynamics: In a multiplayer setting, if a party member possessing the timer logs out, gameplay can be disrupted, leading to a halted dungeon instance. Server timers mitigate this risk. 2. Dungeon Persistence: Players often exit and re-enter dungeons. With a normal timer, exiting erases the timer, jeopardizing the dungeon's progression. Server timers ensure continuity. Why do crashes occur? Server timers, by virtue of their independence, lack character pointers upon invocation. This absence becomes problematic when: Distributing or dropping items. Executing specific chats or commands. Running functions reliant on character pointers. The game struggles to reference a non-existent character, which can either lead to functional anomalies or outright crashes. How can we solve the problem? My way of solving this issue is simple. I've created a global function that when called is selecting the character pointer of the specified PID and returns a boolean of whether it selected it or not. // questlua_global.cpp int _select_pid(lua_State* L) { DWORD dwPID = static_cast<DWORD>(lua_tonumber(L, 1)); quest::PC* pPC = CQuestManager::instance().GetPC(dwPID); if(pPC) { LPCHARACTER lpSelectedChar = CQuestManager::instance().GetCurrentCharacterPtr(); lua_pushboolean(L, (lpSelectedChar ? 1 : 0)); return 1; } lua_pushboolean(L, false); return 1; } { "select_pid", _select_pid }, Now we set the leaderPID as a dungeon flag upon entering the instance for the first time. (if it's not a group, it will set the pid of the player that entered) when login with <PC_IN_DUNGEON> begin if (((party.is_party() and party.is_leader()) or not party.is_party()) and d.getf("leaderPID") < 1) then d.setf("leaderPID", pc.get_player_id()) end end Now when we call the server_timer, we first select the leader and check if we succeeded or not. when give_item.server_timer begin if (d.select(get_server_timer_arg())) then if (select_pid(d.getf("leaderPID"))) then pc.give_item2(19, 1) else -- handle what happends if the selection was unsuccessful end end end That's basically it. You can now call any function in server_timer. How can this get very useful? Let's say we want to create an update timer that constantly updates different information on players client. I've made a function that is pushing each dungeon's member PID. (only if it's in dungeon) #include <functional> struct FDungeonPIDCollector { std::vector<DWORD> vecPIDs; void operator () (LPCHARACTER ch) { if (ch) vecPIDs.push_back(ch->GetPlayerID()); } }; int dungeon_get_member_pids(lua_State* L) { LPDUNGEON pDungeon = CQuestManager::instance().GetCurrentDungeon(); if (!pDungeon) return 0; FDungeonPIDCollector collector; pDungeon->ForEachMember(std::ref(collector)); for (const auto& pid : collector.vecPIDs) { lua_pushnumber(L, pid); } return collector.vecPIDs.size(); } { "get_member_pids", dungeon_get_member_pids }, Using this, we can just update each dungeon's member informations: when dungeon_update_info.server_timer begin if (d.select(get_server_timer_arg())) then local dungeonMemberIds = {d.get_member_pids()}; for index, value in ipairs(dungeonMemberIds) do if (select_pid(value)) then cmdchat(string.format("UpdateDungeonInformation %d %d", 1, 2)) -- pc.update_dungeon_info() else -- handle the negative outcome end end end end
  3. Download Center Github or M2DL Heyo, this is something i did a while ago, perhaps it will be of use for some. [Hidden Content]
  4. Hi, just add me over discord and i'll happly help you ^^
  5. matching monster level (best chances [200]) a bit off monster level (184) iDeltaPercent 200, iRandRange 2000000 iDeltaPercent 184, iRandRange 2000000 iPercent 20000000, iRandRange 2000000 iPercent 18400000, iRandRange 2000000 -- 1000 (mob_drop_chance) iPercent 20000000, iRandRange 2000000 iPercent 18400000, iRandRange 2000000 -- 1000 (mob_drop_chance) iPercent 20000000, iRandRange 2000000 iPercent 18400000, iRandRange 2000000 -- 1000 (mob_drop_chance) iPercent 400000, iRandRange 2000000 iPercent 368000, iRandRange 2000000 -- 20 (mob_drop_chance) iPercent 400000, iRandRange 2000000 iPercent 368000, iRandRange 2000000 -- 20 (mob_drop_chance) iPercent 140000, iRandRange 2000000 iPercent 128800, iRandRange 2000000 -- 7 (mob_drop_chance) I'm pretty sure 100% means "1000" in mob_drop_item not 400 ^^
  6. I can only recommend, professional service!
  7. Yea im not sure what's up with y'all but i closed the poll and you can take a look there, maybe as you said they all troll
  8. The system concept was inspired by Aeldra, however i tried to improve it from it's original version. Huge thanks to @MASTERDOM#3385 for the system elements.
  9. I found this exploit a long time ago, but i never searched why is this happening. My take on it, was to use the pc.remove_item and check if the item is still there. Basically i "avoided" using item.remove and returned if item was not in the inventory. (trash method now but whatever) Anyway, the way you did it is the right way to solve it, thanks marty
  10. Hi, it's a QC syntax issue, it wasn't made to work like this. Try this one instead it should be ok: [Hidden Content]
  11. Hi, why dont you just create a new party func that leaves the party? (Just be careful when you call the Quit party function, check if the group has two members left first and if that's true just Delete the party)
  12. I like the idea but i would go for grid resize and pagination based on item count and size.
×
×
  • 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.