Jump to content

Syreldar

Premium
  • Posts

    1297
  • Joined

  • Last visited

  • Days Won

    38
  • Feedback

    100%

Posts 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.

    • Good 1
  2. 45 minutes ago, strangerino said:

    But with quests, there is no way to use gloves to increase drop rate, or is there a way to increase it?

    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. 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

     

  4. 12 minutes ago, Gurgarath said:

    Absolute chad move, thank you very much, I knew it changed but I was always unable to find anyone able to explain what it exactly was.

    Also, do you have screenshots or information of the entry conditions and stuff? For the scrubs like me who uses official locale_quest?

    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.

    • Love 1
  5. Quote

    With the version 17.3, GameForge implemented new immunity conditions where he gains full damage immunity (MISS) as long as there's even just one of his 4 different Metinstones alive. The Stones still keep their effect, and this makes the Metin of the Mountain (8031) basically useless since it used to increment his damage resistance by 25%.

    The update 21.3 increased the number of Metinstones in the map to 8, it was 4 previously. [Respawn time: 2.5 minutes per stone] I'll include the change in the regen for that. It also changed the dungeon's entry conditions, but since everyone's got different quests for the dungeon, I don't think it's worth putting it here.

    Location: char_battle.cpp -> bool CHARACTER::Damage:

    Below:

    	if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
    		return false;


    Add:

    This is the hidden content, please

    I've also linked the code to a game eventflag, so you can freely disable it by typing the following:

    Quote

    /e ignore_dragonlair_new_immune 1

     

    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.

    • Metin2 Dev 95
    • Eyes 1
    • Facepalm 1
    • Lmao 1
    • Good 13
    • Love 2
    • Love 23
  6. 32 minutes ago, duwen123 said:

    Thank you for your answer! It is very useful for me!

    Yes, perhaps my formulation was not the best.

    I was interested to find out if there is any difference in security between the two projects. Of course both developers promise qualitative security, but I would like to know how it is from a customer's point of view.

    About SQL injection, I know how I can protect the website that is linked to the database, but I remember a certain bug (a long time ago), where someone could do sql inject directly from the client. But again, I've heard about this bug years ago. 😁

     

    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.

  7. 6 hours ago, duwen123 said:
      Reveal hidden contents

     

     

     

     

    Thanks for the advice! I will keep it in mind.

    You mentioned that you worked with both projects. 

    On Martysama's project how easy to modify what you need compared to Owsap's? For example disabling, adding other systems? Compatibility issues when adding certain systems in terms of code? 🤔

    And I guess the security level is high on both projects, right? There is no question of backdoors or being exposed to SQL injections, memory leaks and all sorts of problems common to Metin servers? 🤔

    I'm also still waiting for opinions from other members to get a clearer picture of the situation. 

     

    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.

     

  8. 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.

     

    • Metin2 Dev 1
    • Think 1
    • Lmao 2
  9. 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
        ..
    ..

     

    • Think 1
    • Good 1
    • Love 1
  10. 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).

     

    • Not Good 1
    • Good 1
    • Love 1
  11. Several heads-up, going from top to bottom of the file:

    1. The "enter" trigger is not what you think it is, it's useless in this case, you can remove it.
       
    2. 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.
       
    3. 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.
       
    4. 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.
       
    5. 		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

       

    6. 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

       

    7. 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.

       

    8. 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

       

    9. 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.

    • Metin2 Dev 4
    • Confused 1
    • Good 4
    • Love 1
  12. --[[
        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: https://metin2.dev/topic/29230-syreldars-useful-globals
    ]]
    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

     

    • Love 1
  13. 55 minutes ago, zoowiS said:

    Yes, I understand you, but at certain time intervals it resets all the dungeons that are on the server and the problem is from the source, do you think that what you wrote there solves these problems?

    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.

×
×
  • 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.