Jump to content

caanmasu

Banned
  • Posts

    90
  • Joined

  • Last visited

  • Feedback

    0%

Posts posted by caanmasu

  1.  

    Hello
    With some forum colleagues we have created a command to display the flags of a dungeon for debugging purposes.

     

     

    spacer.png

     

    Usage:

    /dgetf [map_index]

    If map_index is not specified, the index of the current map is taken.

     

    cmd.cpp
    Add:

    ACMD(do_dgetf);


    Add command in list (above of { "\n",): 

    	{ "dgetf",	do_dgetf,		0,		POS_DEAD,	GM_IMPLEMENTOR },



     

    cmd_gm.cpp
    Add this block:

    ACMD(do_dgetf)
    {
    	char arg1[256];
    	
    	one_argument(argument, arg1, sizeof(arg1));
    	
    	if(!ch)
    		return;
    	
    	DWORD mapIndex = ch->GetMapIndex();
    	
    	if (*arg1)
    		str_to_number(mapIndex, arg1);
    		
    	LPDUNGEON pDungeon = CDungeonManager::instance().FindByMapIndex(mapIndex);
    	if (pDungeon)
    	{
    		ch->ChatPacket(CHAT_TYPE_INFO, "Dungeon flag list for %d:", mapIndex);
    		pDungeon->SendFlagList(ch);
    	}
    	else
    		ch->ChatPacket(CHAT_TYPE_INFO, "No dungeon found for mapindex: %d", mapIndex);
    }

     

    dungeon.cpp

    Add this block:

    void CDungeon::SendFlagList(LPCHARACTER ch)
    {
    	for (const auto& [key, val]: m_map_Flag)
    		ch->ChatPacket(CHAT_TYPE_INFO, "%s: %d", key.c_str(),val);
    }


    dungeon.h
    Add below of "void    SetWarpLocation (long map_index, int x, int y);":
     

    	void	SendFlagList(LPCHARACTER ch);



    Greetings.

    • Metin2 Dev 2
    • Love 1
  2. Important!


    Update fix

    Undo fix 1. Put flag CRUSH again. CRUSH is stun in player skill.



    Explication of bug:

    This is the code

    			if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) &&
    				!IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE))
    			{
    				...
    				pkChrVictim->Sync(tx, ty);
    				pkChrVictim->Goto(tx, ty);
    				pkChrVictim->CalculateMoveDuration();
    
    				if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() == (DWORD) pkChrVictim->GetVID())
    				{
    					SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 4, m_pkSk->szName);
    				}
    				else{
    					pkChrVictim->SyncPacket();
    				}

     

     

    You have to start from some facts.

    1. A player skill with the CRUSH flag stuns and pushes at the same time if the victim does not have immunity to blackouts.
    2. If a character is stunned and receives a stun flag, they should not be pushed and should not be turned off again.
    3. If a monster has CRUSH in his skill, he will always push the enemy

    The bug is that the CRUSH skill will always do pushback, whether you have immunity to blackouts or not.
    If a character launches sword strike against another character who is immune to blackouts, he pushes him but does not update packets (the push will not be seen). You can check this by looking at the distance in the syslog. The distance changes, even though it was never pushed.

    The solution is to push only when one character stuns another.
    In case a boss attacks with CRUSH, always push.

    Fix:

    			if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) &&
    				!IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE))
    			{
    				...
    				//We remove the move in all cases.
    				//pkChrVictim->Sync(tx, ty);
    				//pkChrVictim->Goto(tx, ty);
    				//pkChrVictim->CalculateMoveDuration();
    
    				bool bIgnoreStun = pkChrVictim->IsAffectFlag(AFF_STUN); //If the character is already stunned we save in variable
    
    				if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() == (DWORD) pkChrVictim->GetVID())
    				{
    					SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 4, m_pkSk->szName);
    				}
    				//else{
    				//	pkChrVictim->SyncPacket();
    				//}
    				
    				
    				if ((!bIgnoreStun && !(pkChrVictim->GetPoint(POINT_IMMUNE_STUN))) || m_pkChr->IsNPC()) //If the character has no stun and has no immune, or the attack comes from a monster
    				{
    					//Make the push and update packets
    					pkChrVictim->Sync(tx, ty);
    					pkChrVictim->Goto(tx, ty);
    					pkChrVictim->CalculateMoveDuration();
    					pkChrVictim->SyncPacket();
    				}

     

    This fix solve the next bug, too: (double slide)

    https://metin2.download/video/YnRj2vfthxEKq9yGG7ybMWo01bIMp40b/.mp4

    • Metin2 Dev 1
  3. 10 hours ago, mihnea said:

    I don't think it stacks

    Fix:

    char_item.cpp

    Find:
     

    		else if (!IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_DROP) && GetParty())
    		{
    			NPartyPickupDistribute::FFindOwnership funcFindOwnership(item);
    
    			GetParty()->ForEachOnlineMember(funcFindOwnership);
    
    			LPCHARACTER owner = funcFindOwnership.owner;
    			// @fixme115
    			if (!owner)
    				return false;
    
    			int iEmptyCell;


    Add below:

     

    			if (owner)
    			{
    				if (item->IsStackable() && !IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
    				{
    					uint16_t wCount = item->GetCount();
    
    					for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
    					{
    						LPITEM item2 = owner->GetInventoryItem(i);
    
    						if (!item2)
    							continue;
    
    						if (item2->GetVnum() == item->GetVnum())
    						{
    							int j;
    
    							for (j = 0; j < ITEM_SOCKET_MAX_NUM; ++j)
    							{
    								if (item2->GetSocket(j) != item->GetSocket(j))
    									break;
    							}
    
    							if (j != ITEM_SOCKET_MAX_NUM)
    								continue;
    
    							const uint16_t wCount2 = MIN(g_wItemCountLimit - item2->GetCount(), wCount);
    							wCount -= wCount2;
    
    							item2->SetCount(item2->GetCount() + wCount2);
    							if (wCount == 0)
    							{
    								owner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템 획득: %s 님으로부터 %s"), GetName(), item->GetName());
    								ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템 전달: %s 님에게 %s"), owner->GetName(), item->GetName());
    								M2_DESTROY_ITEM(item);
    								if (item2->GetType() == ITEM_QUEST)
    									quest::CQuestManager::Instance().PickupItem(owner->GetPlayerID(), item2);
    								return true;
    							}
    						}
    					}
    					item->SetCount(wCount);
    				}
    			}


    Note: check count datatypes. In my server is wCount2 with uint16_t but in your server likely is bCount2 BYTE

    • kekw 1
  4. Hello

    I found a base bug and I have found its solution. I share it with you with tests.

    Bug 1: Many times when attacking with Sword Strike the damage fails and this damage behavior varies very strange.
    Fix: Remove CRUSH flag from skill_proto (index 20)

    Bug 2: The damage of Sword Strike is too low compared to the other skills of your group.
    Fix: Change eSkillType from MELEE to RANGE in skill_proto (index 20)


    Testing bug 1: https://metin2.download/video/s0Wc1OOpxh7SqbafJtk81nd4BN2QWmCG/.mp4

    • Metin2 Dev 2
    • Scream 1
  5. A client recently asked me for something like this and I sold it to him. I usually help with quests but it wouldn't seem fair to do so out of respect for my client.

    We can make a deal.

    Config looks so:

     

    reward_time = 60, --game time that must be accumulated to earn the coins
    coin_type = "cash", --coin column name in account
    coin_amount = 3, --for every x time (reward_time), x (coin_amount) will be obtained


    I can edit coins for an item

  6. 35 minutes ago, LupoSereno said:

    Thank you for the reply @caanmasu . However, from a player's perspective, what I was hoping for was a simple Python script that I could import into my Python loader. This script should allow me to automatically recall the 'seal' of my pet every time I log in or warp. I understand your explanation from a developer's standpoint, but I'm looking for a more user-friendly solution as a player. If you could provide any guidance or a script to achieve this, it would be greatly appreciated. Thanks again!

    Oh I understand
    I guess I can't help you this time. Only support in the development of the server.
    It's okay, I hope you can make it.

  7. I assume you mean normal pets (not eggs). In any case, the egg ones work in a very similar way in terms of their spawn.

    I am going to give you a guide to resummon the pet after a warp.

    It is advisable to store values that persist, since if you save it in the server's cache (a variable on the server), every time you restart it, all the characters when they enter will have to summon their pet.
    The solution is to save it to the database and the easiest way is to take advantage of the pet_system.quest using flags.

    If you review the code, to invoke the pet you need an item to be selected (when use), that is, the seal, and then through the pet.summon function you send the vnum of the pet (mob_proto) as a parameter.

     

    when [...].use begin
    pc.setqf("pet_item_id", item.get_id()) --stores the id (it's not vnum, it's the id) of the seal. We will use it when we log in and be able to select the seal again
    ...
    --every time you summon the pet, save the vnum of the monster it was summoned with
    pet.summon(mobVnum, false)
    pc.setqf("pet_vnum", mobVnum) --here
    ...
    --every time you unsummon the pet, don't forget to clear the vnum...
    pet.unsummon(mobVnum)
    pc.setqf("pet_vnum", 0) --here
    end

    Now we will make that when the character logs in, it invokes the pet:

    when login with pc.getqf("pet_vnum") != 0 begin --this makes sure we had an active pet last time
    	item.select(pc.getqf("pet_item_id")) --with the seal id flag saved we can select it, it's like executing when use
    	pet.summon(pc.getqf("pet_vnum"), false) --summon the pet with the vnum of the last pet we had active
    end

    The quest side is ready
    Now we need to make sure on the server side that when the pet is uninvoked, the values are cleaned up.

     

    PetSystem.cpp

    In:

    bool CPetActor::Update(DWORD deltaTime)

    Find:

    this->Unsummon();

    And adds:

    m_pkOwner->SetQuestFlag("pet_system.pet_vnum", 0);
    m_pkOwner->SetQuestFlag("pet_system.pet_item_id", 0);

     

    • Metin2 Dev 1
    • Facepalm 1
    • Not Good 1
    • Sad 1
    • Lmao 1
    • Good 1
  8. Src/game

    pvp.cpp

    Add:

    #include "questmanager.h"


    Find:
     

    bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim)
    {

    Add below:
     

    	if (quest::CQuestManager::instance().GetEventFlag("pvp_block_"+std::to_string(pkChr->GetMapIndex())) && pkVictim->IsPC())
    		return false;



    Usage in game:

    Example in map c1

    Activate:

    /e pvp_block_41 1

    Deactivate:
     

    /e pvp_block_41 0


    You can set any map index.

    • Metin2 Dev 1
  9. 1. Cooldown time: 
    item_proto -> value1. Put cooldown time in seconds. Example 5 minutes: 300.

     

    2. Grotto 2 TP: 

    Add your map name in locale.lua (map index 73), then add the variable in select:

    original:

                sub_set = select(town1[empire],town2[empire],locale.map_name[64], locale.map_name[63], locale.map_name[61],locale.map_name[62],gameforge.locale.cancel)
                if sub_set == 7 then -- ´Ý±â
                    return
                end

    new:

                sub_set = select(town1[empire],town2[empire],locale.map_name[64], locale.map_name[63], locale.map_name[61],locale.map_name[62], locale.map_name[73], gameforge.locale.cancel)
                if sub_set == 8 then -- ´Ý±â --put 8 instead 7
                    return
                end

    Add:

                    -- 73 metin2_map_skipia_dungeon_02
                    {
                        { 153600, 1203200 },
                        { 153600, 1203200 },
                        { 153600, 1203200 },
                    },


    Below of:

                    -- 62 metin2_map_n_flame_01
                    {
                        { 153600, 1203200 },
                        { 153600, 1203200 },
                        { 153600, 1203200 },
                    },

                    

    (no tested)

    • Love 1
  10. 3 hours ago, Deiklo said:

    This is a great contribution bro, thank you very much.

    Can this infinity dungeon quest be implemented on other maps? I have that doubt

    Btw, until now you are the person who knows the most about this language and above all, you share it with modesty. keep it up! 🥳

    Hi @Deiklo!
     

    The coding is designed to be customized. You can assign the dungeon map you want, including monsters, rewards, required level, among others.

    To change the map you must modify the infinity_dungeon_lib.data table. It is very easy to do it since the variables are very telling, and in case they are not, I left comments that detail it.

    map_index, map_index_out, base_cords, outside_pos and in each jump of each mission.


    Regarding the compliment, thank you friend, a pleasure to serve you. 🙂

  11. Hello everyone

     

    I bring you my second quest tutorial where you can improve your quest/lua skills (a bit of SQL too) until you become a real expert.

     

    Note: in the attached file is the first and second tutorial (Spanish and English language)

     

    This tutorial is about an infinity Dungeon.

    The dynamic of my tutorials is to make a quest where I show point by point how I would do it, and I explain it in detail.

    If you want to skip the tutorial and just use the quest, you are free to do so, I left a folder with the files to install.

    I must warn that I only provide code, not models. I use already existing models from the game, specifically, demon tower map, Reaper as boss, dogs as monsters to destroy, etc. You can use the dungeon with the models you want, this way you improve the user experience. The dungeon is customizable, you only have to change numbers.

    I must also warn that the dungeon has not been tested with several players, although I did good tests with several of my characters, the best tests are done with real players. In case you find bugs, report them to my Discord.

    Another important note, if you don't read the tutorial, there are additional data that you can't miss, they are really mandatory. You must go to the tutorial and at the end you will find a section called 'Additional data:'. Really, you can't miss it.

     

    The content of this tutorial is as follows:

    1. Show a button on the NPC
    2. Show the NPC button only when we are in the map outside the dungeon.
    3. Create the first dungeon jump
    4. Create group mode
    5. Add some restrictions for entry
    6. Create two room mechanics and run them so that they are chosen randomly.
    7. Take the character out of the dungeon when player die.
    8. Create the ranking log
    9. Add dungeon rejoin
    10. Display the ranking
    11. Add an announcement when someone breaks a floor record.
    12. Create spectator mode
    13. Increase the difficulty for each floor
    14. Add logs
    15. Create rewards
    16. Create 5 dungeon mechanics
    17. Dynamize the base coordinates
    18. Add remaining time on each floor
    19. Facilitate entry into GMs characters
    20. Convert texts to variables

     

    Some gifs:

    Spectator mode

    Dugeon ranking

    Rejoin

    Announcement when someone breaks a floor record

    Mission 1: killAllMonsters

    Mission 2: killBossWithMonsters

    Mission 3: killAllStones

    Mission 4: purgePillarsRightOrder

    Mission 5: findRightKey


    Number of lines of code:

    translate.lua: 48
    questlib.lua: 76
    quest_infinity_dungeon.sql: 9
    infinity_dungeon.quest: 167
    infinity_dungeon_lib.lua: 408
    infinity_dungeon_mission_lib.lua: 287
    infinity_dungeon_rewards.lua: 26

    Total: 1021 lines


    If you liked the intention of this post you can help me with a reaction, so you can give more popularity to this post and make it more visited so that more people can access to the knowledge of free quest/lua of the highest quality ever seen.

    Once an acquaintance told me that there was not enough quest documentation for Metin2 and I agreed with him. At that time I knew a little about quest/lua but I said to myself 'knowledge should be free but someone should provide it, not for profit' and I didn't expect that I was going to do it. I didn't want to be left alone with what I knew, I had the need to share it for everyone.

     

    About my knowledge of quest/lua:
    When I first learned quest/lua, I already had base experience of programming in general. I learned quest/lua empirically by watching other people's quest, the LUA source code in C++ about functions and the binary source code related to RAW TEXT tokens, in that order. I could say that I have seen and reviewed thousands of quests written by German, Spanish, English, Romanian, Turkish and other nationalities. I have also seen all levels of quests written by others. I have created many quests for clients, of all kinds of nationalities for all kinds of servers.
    In total I have accumulated more than 10 thousand hours of quest/lua programming. I have dedicated a lot of time of my life to this. I am a person who does not stay with what he knows, but wants to extend himself more, so I researched for a long time how to improve the quality of my code and to this day I put it into practice and it is the most important pillar of all my programming: code quality.
    I learned many code structures from many quest until I created my own structure and also my own libraries. When quest/lua is limited to what I need, I have no difficulty in modifying or creating LUA functions in C++ as this is also part of quest.

    There is much more about this but I think it is enough in this post.

    The day I leave, there will be forever (or until Metin2 dies completely) this knowledge that will be useful to improve the experience of players in Metin2 private servers. If they are shit server or not, I don't care.

    If you need any help you can contact me. My Discord is 'caanmasu'.

    Greetings to all.

    Download: https://acortar.link/bBp1hk or 

    This is the hidden content, please

    • Metin2 Dev 51
    • Eyes 1
    • Good 8
    • Love 4
    • Love 36
  12. Test video: https://metin2.download/video/V8IB9aKVySF877MWJuZADyj09N0iw3O6/.mp4

     

    upgrade_skills.quest

    quest upgrade_skills begin
    	state start begin
    		when 50513.use begin
    			upgrade_skills.upgradeSkillDialog(1)
    		end
    		
    		when 50512.use begin
    			upgrade_skills.upgradeSkillDialog(40)
    		end
    		
    		function upgradeSkillDialog(inc)
    			if pc.get_skill_group() != 0 then
    				local vnum_list, name_list = {}, {}
    				for _, vnum in ipairs(special.active_skill_list[pc.job+1][pc.get_skill_group()]) do
    					if pc.get_skill_level(vnum) < 40 then
    						table.insert(vnum_list, vnum)
    						table.insert(name_list, locale.GM_SKILL_NAME_DICT[vnum] or vnum)
    					end
    				end
    				if table.getn(name_list) != 0 then
    					table.insert(name_list, "Close")
    					say_title("Upgrade skill")
    					say_reward("[ENTER]Item disappear after use")
    					local sel = select_table(name_list)
    					if sel != table.getn(name_list) then
    						pc.set_skill_level(vnum_list[sel], pc.get_skill_level(vnum_list[sel])+inc)
    						pc.remove_item(item.vnum)
    					end
    				end
    			end
    		end
    	end
    end

     

  13. This is my Hyperlink

    https://metin2.download/picture/WLSP0GxK4LZG4zvqD7EXfE8nipys854f/.gif

    I can't help you directly.
    It takes time to find the solution but it is very likely that the error is there.
    You must review the flow of the code very well and know the values of the variables.
    Patience and tests.
    I can't help you here, sorry.

  14. Hello everyone
     

    I bring a contribution to the quest section that in my opinion will be very useful for all the levels that I have seen in the forums that I have known.

    I saw some people who are just learning and some who are very talented, and I'm sure they'll tap into their potential with this hands-on tutorial.

    It's totally worth it. I did the Spanish version and it was a success.
    Now the English version, let's see how it goes.

    The minimum knowledge that you must have to perform this tutorial is to know how to compile the quests and optionally the source code on the server side.

    My recommendation to read the tutorial is that you first read it superficially from the beginning to the end, and then start from the beginning to the end applying the steps.

    The tutorial is about a real case I had with one of my clients, and he gave me permission to share it. Although the way of explaining is not how I would really do it, I made it easier to understand with the aim of teaching.

     

    Test video:

    https://metin2.download/video/cd08UBm4t16ogVA7cvO1Ag3HKijS0yL5/.mp4

     

    Any questions or requests you have about me or my work, I will gladly reply to the private message of this forum.

     

    This is the hidden content, please
     or 
    This is the hidden content, please

     

    Love and peace for everyone.

    • Metin2 Dev 76
    • Eyes 6
    • Good 19
    • Love 3
    • Love 38
  15. char_resist.cpp

    Find:

     

    EVENTFUNC(poison_event)
    {
    	TPoisonEventInfo * info = dynamic_cast<TPoisonEventInfo *>( event->info );
    
    	if ( info == NULL )
    	{
    		sys_err( "poison_event> <Factor> Null pointer" );
    		return 0;
    	}
    
    	LPCHARACTER ch = info->ch;
    
    	if (ch == NULL) { // <Factor>
    		return 0;
    	}
      
      	LPCHARACTER pkAttacker = CHARACTER_MANAGER::instance().FindByPID(info->attacker_pid);

    Change this line:
     

    	LPCHARACTER pkAttacker = CHARACTER_MANAGER::instance().FindByPID(info->attacker_pid);

    For:

     

    	LPCHARACTER pkAttacker = CHARACTER_MANAGER::Instance().Find(info->attacker_pid);
    
    	if (!pkAttacker)
    		return 0;

     

    Find:

    void CHARACTER::AttackedByPoison(LPCHARACTER pkAttacker)
    {
    	if (m_pkPoisonEvent)
    		return;
    
    	if (m_bHasPoisoned && !IsPC())
    		return;
    
    #ifdef ENABLE_WOLFMAN_CHARACTER
    	if (m_pkBleedingEvent)
    		return;
    
    	if (m_bHasBled && !IsPC())
    		return;
    #endif
    
    	if (pkAttacker && pkAttacker->GetLevel() < GetLevel())
    	{
    		int delta = GetLevel() - pkAttacker->GetLevel();
    
    		if (delta > 8)
    			delta = 8;
    
    		if (number(1, 100) > poison_level_adjust[delta])
    			return;
    	}
    
    	/*if (IsImmune(IMMUNE_POISON))
    	  return;*/
    
    
    	m_bHasPoisoned = true;
    
    	AddAffect(AFFECT_POISON, POINT_NONE, 0, AFF_POISON, POISON_LENGTH + 1, 0, true);
    
    	TPoisonEventInfo* info = AllocEventInfo<TPoisonEventInfo>();
    
    	info->ch = this;
    	info->count = 10;
      	info->attacker_pid = pkAttacker ? pkAttacker->GetPlayerID() : 0;

    Change this line:

    	info->attacker_pid = pkAttacker ? pkAttacker->GetPlayerID() : 0;

    For:

    	info->attacker_pid = pkAttacker ? pkAttacker->GetVID() : 0;

     

  16. This occurred because of a recent Visual Studio update.

    Solution:

    Right click on the project UserInterface -> Properties -> C/C++ -> Precompiled Headers -> Precompiled Header: Do not use precompiled headers.

    Do the same with the other projects (ScriptLib, SpeedTreeLib, etc)

    Do the same in Release and Debug.

     

    • Think 1
  17. Hi @mrtcnglrr

    Search:

     

    			if (pAttacker->GetPoint(POINT_STEAL_HP))
    			{
    				int pct = 1;
    
    				if (number(1, 10) <= pct)
    				{
    					int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
    
    					if (iHP > 0 && GetHP() >= iHP)
    					{
    						CreateFly(FLY_HP_SMALL, pAttacker);
    #ifdef YOUR_DEFINE
    						if (!IsNPC())
    						{
    							pAttacker->PointChange(POINT_HP, iHP);
    							PointChange(POINT_HP, -iHP);
    						}
    #else
    						pAttacker->PointChange(POINT_HP, iHP);
    						PointChange(POINT_HP, -iHP);
    #endif
    					}
    				}
    			}


    What I did in this code was omit the HP absorb damage on the monsters.

    Works.

    • Love 1
  18. 9 hours ago, backtop said:

    Thank you for your help 🙂 But I don't have the function item.set_attribute in questlib.lua can you share this function?

    Don't bother using functions that don't exist in your source code.


    There is a function for that, it uses:

    item.set_value(index, apply_type, apply_value)

     

    Like this:
     

    item.set_value(0, 72, math.min(MAX_AVG_DMG, START_AVG_DMG + PROG_AVG_DMG*pc.getqf("times")));

     

    • Good 1
  19. Hi @backtop

    Many times the structure of the data is complicated, and anyone would do this:

    --Weapons lvl 1
                local weapons = {
                    [0] = {21900, 21903},
                    [1] = {21900, 21901, 21902},
                    [2] = {21900},
                    [3] = {21904, 21905},
                }
    --Weapons lvl 10
                local weapons = {
                    [0] = {21910, 21913},
                    [1] = {21910, 21911, 21912},
                    [2] = {21910},
                    [3] = {21914, 21915},
                }
    --Weapons lvl 20
                local weapons = {
                    [0] = {21920, 21923},
                    [1] = {21920, 21921, 21922},
                    [2] = {21920},
                    [3] = {21924, 21925},
                }
    --...

    To fix this problem, you need to find the pattern.

    You must somehow relate the vnum of the weapon to its "jump". The jump corresponds to the count of the times the reward has been collected. It will start at 0 by default and it suits us for being a qf.
    In my case I called it "step".

    21900+step*10

    I think it is understood.

    Regarding the type of weapon, I have "dynamized" it.
    On the line:

    local weapon_type = {{0, 3}, {0, 1, 2}, {0}, {4, 5}, {6}}

     

    The order remains the same, only when I call pc.job, I add 1 to it to match.
    The number that is inside each table, for example, {0, 3}, corresponds to the type of weapon, these numbers being the last digits of the weapon's vnum.

    In this way I have dynamized the code.

    There are good contributions in this thread, take the attributes of average damage and ability to complement your code.

    I've done a 31 line quest in case you want to review it. I must warn you that the code is not tested and most likely contains bugs. This code is a guide.

    But don't worry, a quest that has a lot of code or not, does not influence the server, and also nobody will be able to know it. The important thing is that things work.

    quest young_weapon_heroes begin
    	state start begin
    		when letter or levelup with pc.level >= pc.getqf("step")*10 and pc.getqf("step") <= 7 begin
    			send_letter(locale(82))
    		end
    		
    		when button or info begin
    			say_title(locale(82))
    			say(locale(84))
    			wait()
    			say(locale(85))
    			local weapon_type = {{0, 3}, {0, 1, 2}, {0}, {4, 5}, {6}}
    			local my_weapon_type = weapon_type[pc.job+1]
    			local t_select = {}
    			for i = 1, table.getn(my_weapon_type) do
    				local weapon_vnum = 21900+pc.getqf("step")*10+my_weapon_type[i]
    				say_item_vnum_inline(weapon_vnum, i-1, table.getn(my_weapon_type))
    				table.insert(t_select, item_name(weapon_vnum))
    			end
    			table.insert(t_select, "Close")
    			local sel = select_table(t_select)
    			if sel == table.getn(t_select) then
    				return
    			end
    			pc.give_item2_select(21900+pc.getqf("step")*10+my_weapon_type[sel])
    			pc.setqf("step", pc.getqf("step")+1)
    			--add mean skill
    			clear_letter()
    		end
    	end
    end


     

     

    • kekw 1
    • Facepalm 1
    • Love 1
×
×
  • 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.