Jump to content

Syreldar

Premium
  • Posts

    1295
  • Joined

  • Last visited

  • Days Won

    38
  • Feedback

    100%

Everything posted by Syreldar

  1. What the comment above said is absolutely untrue by the way. Using my old server as experience, taking into account all drops for all map on all level ranges for all the characters of my server (iirc ~450 people online at the same time on average), I've never suffered any kind of lag issue, and the machine I used to run the server was mediocre at best. Not only that, writing drops in Lua has many advantages over C++ such as no need to recompile for every small change. Lua is also the fastest scripting language, but execution speed doesn't play a factor here. It's metin2 we're talking about. Unless you bottleneck the core itself by making infinite loops or things of the sort (which btw won't generate lag but will crash the core altogether), you won't run in any lag issue whatsoever.
  2. Sure, you can. You can also add more items with different effects on the droprate.. specific events.. etc. Many people use sources even for the smallest of things nowadays, but I can assure you that there's rarely something you can't do via quest.
  3. Quests have no impact on the server stability. If well-coded that is. You can make a full mob_drop_item coded in Lua without issues. One of my servers had full quest drops.
  4. Introducing.. Quests! *Insert sounds of trumpets, cymbals, drums and orchestra* quest random_drops_yay begin state start begin when kill with not npc.is_pc() begin local items = {80001, 80002, 80003}; for index = 1, table.getn(items) do if (math.random(100) <= INSERT_YOUR_DROPCHANCE_HERE) then game.drop_item_with_ownership(items[index], 1); -- pc.give_item2(items[index], 1); will make them pop up in the inventory directly. break; -- If you don't want to limit 1 drop per monster, comment this line. end -- if end -- for end -- when end -- state end -- quest
  5. Sure, basically they made it so the dragon is no longer exclusive to one group per hour, but free-access (meaning it's not a global room anymore, but an instanced dungeon), and people can enter up to 6 times per day following these criteria: Minimum level: 75 (unchanged) Each member of the party needs to have: - 5x Spiral Key (vnum 30179). +If it's the first time they enter for that day: 5x Spiral Key (vnum 30179). +If it's not, they can enter up to 5 additional times that day by giving 70x Dragon's Temple Entry (vnum 71122) to the Spirit of a Sura NPC each time they enter. Meaning a total of 350 units if they wanna enter all 5 additional times for that day. It's really easy to code via quest.
  6. Location: char_battle.cpp -> bool CHARACTER::Damage: Below: if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK)) return false; Add: [Hidden Content] I've also linked the code to a game eventflag, so you can freely disable it by typing the following: And in the regen [data/dungeon/dragon_lair.txt]: r 170 160 15 15 0 0 150s 5000 1 8001 r 190 180 15 15 0 0 150s 5000 1 8001 r 170 160 15 15 0 0 150s 5000 1 8001 r 190 180 15 15 0 0 150s 5000 1 8001 r 170 160 15 15 0 0 150s 5000 1 8001 r 190 180 15 15 0 0 150s 5000 1 8001 r 170 160 15 15 0 0 150s 5000 1 8001 r 190 180 15 15 0 0 150s 5000 1 8001 HF.
  7. Okay, but you gotta prove you bought it, and not leeched it, if you want support from here.
  8. Owsap's licence checks won't crash your server, dunno where u got that from.
  9. Overall, when we talk about security we mean system security, which has still little to do with the actual files. You might contact Shogun to get a service on system configuration and protections. To my knowledge he's the most qualified in that field in here. Can't say I remember this "client sqli" you talk about. But it's safe to say they both fixed it.
  10. If it is plechito's dungeon and you can prove you bought it from him, i will gladly help you.
  11. Disabling systems is as simple as commenting a define, implementing systems might be simpler on Marty's files because they're more "vanilla", it might be tougher on Owsaps files because much of the code is changed, so when following a guide to install a system that tells you for example to "add this below this code", you might be lost since these guides usually use fresh clients as base to write their examples off of, for the same reason there could be compatibility issues with Owsaps client because he's got many reversed functions and some have also been rewritten, like tooltip width management for items. In the end it comes down to your knowledge and ability to adapt. So in short, it might be way easier to install systems on Martysama's files if you're inexperienced. I do not understand the question that follows though, why would there be backdoors? And being exposed to sql injection has little to do with the files and more to do with how properly the main site is coded.
  12. function FilesToChoose() if (MoneyIsAProblem() or not NeedMoreOfficialSystems()) then return MSF; end -- if return OSF; end -- function They're both highly skilled and competent developers. In my opinion, in the end, the main difference comes down to price and number of systems their files are equipped with. Owsap also has a very active discord where we discuss about features, bugs, suggestions, etc. on a daily basis; Marty also has a discord but it's very different (not really focused on Marty's files, it's more like a mini community) and it's not as active as Owsap's. So that's up to you to decide, based on what you wrote, I'd say that if you value support and activity a lot and money's not an issue, then OSF's for you. If you don't and/or feel like they cost way too much, then Marty's files are better for you since you don't need many systems, so you would end up paying less. I bought both of their files in the past, I firmly support them and I will always vouch for both of them as people and as developers. But, if I were to choose one's files it would be Owsap's, solely because of the daily activity on the Discord, frequent and free updates (Marty's updates aren't free if I remember correctly), and many more systems to work with, either written by him or extremely trusted and competent people, which I can disable if I don't like.
  13. Reversing their code like we do with root meta files and binary funcs is not possible, quests are stored server side, only the dialog isn't. You can replicate it, not get it directly.
  14. Well automatically no. But as long as you have a client and a character to test how they work in game and a good quester, you can replicate them 101. You can also find the quests' lines of dialog inside the official locale.
  15. With this feature, you can easily check a list of values and iterate them within triggers without needing to create global vars or functions. Real handy. For example, let's say you have an item that you want to drop from specific dungeons' monsters, here's a one-liner: define DROP_CHANCE 2 define ITEM_VNUM 30271 define group DROP_DUNGEONS_INDEXES [1, 21, 41] .. .. when kill with not npc.is_pc() and pc.in_dungeon() and table_is_in(DROP_DUNGEONS_INDEXES, math.floor(pc.get_map_index() / 10000)) and math.random(100) <= DROP_CHANCE begin game.drop_item_with_ownership(ITEM_VNUM, 1); end -- when .. ..
  16. The problem is at the root, to my experience there are three kinds of people who buy serverfiles. The first kind are the ones who buy the first files they see when typing "metin2 serverfiles", without caring about the price, they are the ones who get scammed more often cause they can't even bother doing some research on the seller and their trustworthiness. (example: the guy who made this thread) The second kind are the ones who know exactly who the trustworthy ones are, but they won't buy them cause such files don't include all the bullshit systems you can find online, and they can't be arsed implementing them by themselves/buying them. But guess whose files are FULL of all the systems you can find online? You guessed it, professional copypasters and scammers', like Trinity. The third kind still knows exactly who the trustworthy ones are, but they refuse to buy them and end up getting their shit online and/or contacting random "devs" to buy their serverfiles. Why? Cause they cost less than the trustworthy option. All three of them get scammed all the same. You might hate me for telling the truth but that's just how it is: if you wanna build a server you need at least basic knowledge of the scene and money (like real good money, you can't afford to cut on anything, cause the first time you decide to buy a system from a less trustworthy person just cause it costs less you're completely fucked. A single bad system can fuck your server over, burning all the money you've expended so far. People like @MentaLL know exactly what it means).
  17. I'm afraid I don't understand the question. You need a guide to explain you.. math?
  18. It can't work if you have no idea how quests work in the first place. Also none of the aforementioned solutions is correct.
  19. Several heads-up, going from top to bottom of the file: The "enter" trigger is not what you think it is, it's useless in this case, you can remove it. Not sure what's the point of writing d.set_warp_location(DUNGEON_MAP_INDEX, 12319,13341), the correct way to use it is to define the coordinates of the map_index where you want the player to be sent to in response to a d.exit() call. For example, the devil tower uses it to send the player outside of the tower near the entry NPC, meanwhile you're using it with the same destination index as the dungeon itself. You use multiple d.set_minimap_dungeoninfo_status and d.spawn_mob calls in a single trigger, you can just make a function for the first one, and make a generic array for the second one which you can later use to spawn monster recursively via a simple for cycle, this way not only you avoid repetition but you also add a certain degree of customizability to the script. when 8005.kill with d.getf("deathhall_stage") == 1 begin Here you didn't specify the dungeon instance in which the script should be triggered, this leads to errors if the monster is present in the normal world, and can also lead to conflict in case you use the same monster in multiple instances. I see you did it for some of the triggers that follow, but always make sure you leave none unchecked, there's a couple more triggers that need it. when 304.kill with d.getf("deathhall_stage") == 3 and death_hall.isInDungeon(DUNGEON_MAP_INDEX) begin local count_pillar = d.getf("pillar_stone_flag") - 1 d.setf("pillar_stone_flag", count_pillar) if contains({0, 100, 200, 300}, count_pillar) then pc.give_item2(PILLAR_STONE, 1) d.set_minimap_dungeoninfo_notice("Benutze den Schlüsselstein mit rechtsklick") end end Assuming contains() uses a for loop to check recursively, you have adopted an O(n) approach for no reason at all. I will provide two O(1) solutions for your learning: For the first one, we'll use a set data structure: when 304.kill with d.getf("deathhall_stage") == 3 and death_hall.isInDungeon(DUNGEON_MAP_INDEX) begin local count_pillar = d.getf("pillar_stone_flag") - 1; d.setf("pillar_stone_flag", count_pillar); local pillars = { [0] = true, [100] = true, [200] = true, [300] = true }; if (pillars[count_pillar]) then pc.give_item2(PILLAR_STONE, 1); d.set_minimap_dungeoninfo_notice("Benutze den Schlüsselstein mit rechtsklick") end -- if end -- when For the second one, since these values are all multiples, we can use the math.mod func. when 304.kill with d.getf("deathhall_stage") == 3 and death_hall.isInDungeon(DUNGEON_MAP_INDEX) begin local count_pillar = d.getf("pillar_stone_flag") - 1; d.setf("pillar_stone_flag", count_pillar); if (math.mod(count_pillar, 100) == 0 and count_pillar <= 300) then pc.give_item2(PILLAR_STONE, 1); d.set_minimap_dungeoninfo_notice("Benutze den Schlüsselstein mit rechtsklick") end -- if end -- when We can see here another case of repetition: if count == 4 then d.set_minimap_dungeoninfo_gauge(0,0,0) d.set_minimap_dungeoninfo_notice("Du hast einen Torschlüssel erhalten. Ziehe ihn aufs Tor.") d.kill_all() item.remove(PILLAR_STONE, 1) pc.give_item2(DOOR_KEY, 1) d.setf("door_key_flag", 1) else d.set_minimap_dungeoninfo_gauge(1,d.getf("stones_use_flag"),4) d.set_minimap_dungeoninfo_notice("Vernichte solange Monster bis du einen Schlüsselstein droppst!") item.remove(PILLAR_STONE, 1) d.kill_all() d.regen_file("data/zylon_dungeon/zylon_regen02.txt") d.regen_file("data/zylon_dungeon/zylon_regen_s.txt") end Move the calls you're doing in any case outside of the if blocks, like this: item.remove(PILLAR_STONE, 1) d.kill_all() if count == 4 then d.set_minimap_dungeoninfo_gauge(0,0,0) d.set_minimap_dungeoninfo_notice("Du hast einen Torschlüssel erhalten. Ziehe ihn aufs Tor.") pc.give_item2(DOOR_KEY, 1) d.setf("door_key_flag", 1) else d.set_minimap_dungeoninfo_gauge(1,d.getf("stones_use_flag"),4) d.set_minimap_dungeoninfo_notice("Vernichte solange Monster bis du einen Schlüsselstein droppst!") d.regen_file("data/zylon_dungeon/zylon_regen02.txt") d.regen_file("data/zylon_dungeon/zylon_regen_s.txt") end The following is another mistake many people make (also same mistake as .4): when 8008.kill with d.getf("door_key_drop") == 1 begin local pct = number(1,10) if pct == 1 then pc.give_item2(DOOR_KEY, 1) d.set_minimap_dungeoninfo_notice("Du hast einen Torschlüssel erhalten. Ziehe ihn aufs Tor.") d.setf("door_key_flag", 2) clear_server_timer("time_out", get_server_timer_arg()) elseif pct != 1 then d.regen_file("data/zylon_dungeon/stone_regen.txt") end end get_server_timer_arg() only works inside of a server_timer, not outside of it, so this code won't clear the time_out server_timer. When trying to clear a server_timer outside of another server_timer's scope, use d.get_map_index(), since the timer's arg will for sure be the instance's map_index itself. Not really an error but this will make any rejoin system not work, since you're clearing the dungeon and its flags, clearing flags is also pointless, see (.9) for an explanation: when logout begin if death_hall.isInDungeon() then death_hall.clearDungeon() end end Again, the same error as before (potentially calling get_server_timer_arg() outside of a server_timer's scope) : function clearDungeon() d.setf("deathhall_stage", 0) d.setf("boss_stage", 0) d.setf("door_key_flag", 0) d.setf("door_key_drop", 0) d.setf("metinstone_count", 0) d.setf("monster_count", 0) d.setf("pillar_stone_flag", 0) d.setf("stones_use_flag", 0) d.set_minimap_dungeoninfo_gauge(0,0,0) d.kill_all() d.clear_regen() clear_server_timer("dungeon_end", get_server_timer_arg()) clear_server_timer("time_out", get_server_timer_arg()) end the two clear_server_timer calls won't work when called outside of a server_timer, see the "logout" trigger. Use d.get_map_index() when calling the func outside of another server_timer's scope, clearing flags is also useless as I mentioned in (.8). Why is clearing flags/timers upon finishing a dungeon useless?: An abandoned instance won't be accessible to players until deleted (~5 minutes since last activity usually, check the dungeon_dead_event in dungeon.cpp), since d.new_jump/d.new_jump_party/d.new_jump_all will always create a new one. And, when deleted, the flags will reset automatically and the timers will also automatically clear themselves, meaning players will never be able to enter an instance with pre-set flags from a past user via d.new_jump/d.new_jump_party/d.new_jump_all. This practice of resetting flags/timers upon ending a dungeon is something we now only see in official quests (or from bad and clueless coders) and is likely practice from past times that is now obsolete.
  20. --[[ Returns: An array containing 2 subarrays: - The first subarray, vnum_list, contains the vnums of the skills; - The second subarray, name_list, contains the names of the skills; Needs: [Hidden Content] ]] BuildSkillList = function(job, group, min_level, max_level) local vnum_list = {}; local name_list = {}; if (not job) then job = pc.get_job(); end -- if if (not group or group == 0) then group = DOCTRINE_1; end -- if if (not min_level) then min_level = BASE_SKILL_LEVEL; end -- if if (not max_level) then max_level = PERFECT_MASTER_SKILL_LEVEL; end -- if local skill_level = 0; local skill_list = ACTIVE_SKILL_LIST[job][group]; for _, skill_vnum in ipairs(skill_list) do skill_level = pc.get_skill_level(skill_vnum); if (skill_level >= min_level and skill_level <= max_level) then table.insert(vnum_list, skill_vnum); table.insert(name_list, SKILL_NAME_TABLE[skill_vnum]); end -- if end -- for return {vnum_list, name_list}; end -- function
  21. 29/01/2023: Rewritten. Added some new stuff. Provided more examples and data for each func.
  22. All I see here is a Lua error cause that is all the info you provided. I'd start by fixing that; then, if you keep having the issue, provide the system's files and further information / data about the error you are experiencing.
  23. You are treating a 'd' var as an array when it is in fact a number. That's about it.
×
×
  • 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.