Jump to content

Braxy

Bronze
  • Posts

    182
  • Joined

  • Last visited

  • Days Won

    7
  • Feedback

    0%

Everything posted by Braxy

  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.
  13. Since you are selecting, you are inserting information into two local variables. Information such as affected_rows and the values of those rows (affected_rows, goldd). You can access the values from index 1 to (affected_rows) and the specific name. Ex: local affected_rows, goldd = mysql_direct_query("SELECT gold FROM player.player WHERE account_id = '2';") say_reward(tostring(goldd[affected_rows]["gold"])) In this example we are accessing table index by affected_rows because in our case you can only select the gold from account_id 2.
  14. local inputPrice = tonumber(string.gsub(input(), "[^0-9]", "")) local realPrice = math.floor(inputPrice) There is no logic explanation for the math.floor since you only let people write numbers but you can let that be there just in case.
  15. Competent people, fast service and good quality. Highly recommended.
  16. Hi, i like the idea. Anyway, the way you tought the logic for it is not ideal. In my opinion you can do this by initializing the selection in LUA when Booting the server and then just refering to the specific memory on Login event.
  17. Well, this is not quite true. The buyer is opening a dispute with the seller, if the dispute is not solved by the both seller and buyer then Paypal intervenes. The instant block is as i said, made automatically by the system when you have over 50-60 cases opened in a short time (two days or so) (doesn't matter if you reply to them or not) Now you might ask, how in the world am i gonna get this ammount of refunds. Well if you have a big server this is not a big deal what so ever. Everything i said, is from a personal experience so trust me, i've been there. Imagine people donating and playing with hacks, when the admins are banning them they all refund their money. Paypal is one of the worst payment's method out here.
  18. Everything you said is right, until one point. If the players are refunding the money (romanian's are doing this alot) the account will be blocked for 180 days accepting every refund instantly without any chance to prove it's wrong. The problem is that this happends automatically by the system, so for example if people are refunding like 50-60 payments your account will instantly be blocked leaving you without any way to contact them and even if you try to, they will send you the same message over and over again.
  19. You know.. i don't really care about all of this. You are obviously frustrated. I will let the higher people decide whatever happends (tho im sure you have contacts and you can pull strings around here) Have a nice day
  20. You know.. i don't really care about all of this. You are obviously frustrated. I will let the higher people decide whatever happends (tho im sure you have contacts and you can pull strings around here) Have a nice day
  21. BASED on your way of indexing data into library but it was my own logic for the whole dungeon ahahha im done with you bro
×
×
  • 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.