Jump to content

Alina

Inactive Member
  • Posts

    174
  • Joined

  • Last visited

  • Days Won

    13
  • Feedback

    0%

Posts posted by Alina

  1. M2 Download Center

    This is the hidden content, please
    ( Internal )

    Hey everybody,

     

    I have something special for you. This time I'm gonna show you how to change the appearance of your horses on the fly! :D

     

     

    *** Disclaimer (kinda) ***

     

    I hereby declare that the changes I made are all by myself. I did not steal from anyone. Therefore for this guide I am the author. If anyone wants to copy my guide and post it anywhere he's free to do as long as he mentions the original author. I do not provide or share the source code or anything else protected by copyright.

     

    If something breaks I'm not the one to blame at. Always make sure to test changes. Never implement them on production releases, always use test distributions before! If you find any flaws, may it be regarding security or something else you're free to tell me so. I'm learning, as we all do, so I'm in no way too proud to admit I'm making mistakes. I'll correct them as soon as possible of course.

     

     

    1) Which files do we need to edit?

    - char.h

    - char.cpp

    - char_horse.cpp

    - questlua_horse.cpp

    - tables.h (in common)

    - ClientManagerPlayer.cpp (in db)

     

    2) What are we planning to do?

    Simple problem: I for myself hate it to use thousands of seals, switch between them, maybe have bugs and I think it's not that good solved to use an additional "system" to let players ride pets.

    So what do we want to do? We want to make the appearance of horses variable, so players can for example use seals to change the appearance of their horses instead of mounting an additional "horse".

    So. How are we going to do this? Simple! We can just add a variable to our character class, so the gamefile will know what appearance the players horse is like. We only need to change a bit here and there and the magic will apply! :)

     

    3) Adding the new variable and make it work

    First let's add a new variable to store the horse appearance. We'll do it with SQL, so when the player sets a horse appearance, it'll be saved. This is the "horse-variable" (yeah damn, I can invent cool and catchy names!). Open tables.h and add the following line into the struct of SPlayerTable (you can add it anywhere, I just added it beyond the declaration of sRandomSP)

     

    DWORD sHorse_appearance;

     

    Now we already can close tables.h and save it.

     

     

    Next open ClientManagerPlayer.cpp and find:

    "random_sp = %d, "
    

    and add below:

    "horse_appearance = %u, "

    Then scroll a little bit down and you'll find

     

    pkTab->sRandomSP,

    Add below:

    pkTab->sHorse_appearance,

     

    Next search for:

    "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"

    And change this line to

    "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,horse_appearance,playtime,"
    

     

    Then search for:

    str_to_number(pkTab->sRandomSP, row[col++]);

    And add below:

    str_to_number(pkTab->sHorse_appearance, row[col++]);

     

    Then search for exactly this:

    "hp, mp, random_hp, random_sp, stat_point, stamina, part_base, part_main, part_hair, gold, playtime, "

    and replace it with:

    "hp, mp, random_hp, random_sp, horse_appearance, stat_point, stamina, part_base, part_main, part_hair, gold, playtime, "

     

    And a few lines down to that we can find

    packet->player_table.sRandomSP, 

    There we add:

    packet->player_table.sHorse_appearance, 

     

     

    You can close ClientManagerPlayer.cpp now and open char.h.

    There we search for struct character_point and add below

    int iRandomSP;

    the following line:

    unsigned int horse_appearance;

     

    Let's close char.h and open char.cpp. Find

    tab.sRandomSP = m_points.iRandomSP;

    and add below:

    tab.sHorse_appearance = m_points.horse_appearance;

     

    Next find

    m_points.iRandomSP = t->sRandomSP;

    and add below again:

    m_points.horse_appearance = t->sHorse_appearance;

     

    That's all for the source part in this stage! :)

    You'll only have to add a new column called horse_appearance to your player-table (and player_deleted of course! :D). Data type is unsigned int(6) default 0.

     

    You'd now be able to compile the gamefile and run it without any flaws. Nothing has changed yet, but this will come in the next part ;)

     

     

    4) Use our new variable ;)

    In this part we'll create two functions, one gets the horse appearance and one sets it. Also we'll change our horse appearance function so the source will now redirect it to our new variable - if we set it. So the trick on this is, that normally the default value is 0. So if no vnum has been set the gamefile will instead use the normal horse_table like it did before. But if we set a vnum, it'll instead use that.

    Let's begin with the two new functions. Open char.h and add anywhere in public section (I added it below the GetHP() function):

    		DWORD	GetHorseAppearance()	{ return m_points.horse_appearance; }
    		void	SetHorseAppearance(DWORD vnum)	{ m_points.horse_appearance = vnum; }
    

     

    These are our new functions.

    We'll use them in the GetMyHorseVnum() function, but first we need to remove it's constness.

    In the same file find:

    virtual DWORD GetMyHorseVnum() const;

    and remove the const. So it looks like:

    virtual DWORD GetMyHorseVnum();

     

    That's all we need now, we can just close char.h and move on to char_horse.cpp.

     

     

    Find

    DWORD CHARACTER::GetMyHorseVnum() const

    and remove it's constness:

    DWORD CHARACTER::GetMyHorseVnum()

    and at the beginning of the function we just add:

    	if((DWORD horse_looks = GetHorseAppearance()) > 0)
    		return horse_looks;
    

     

    Save it and close it. That's all :) Now, if you change the horse_appearance in your database, you'll notice the new horse appearance ingame! :)

     

    5) Adding the questfunctions

    At last we want to be able to edit the horse appearance on the fly so we can use items like seals to set it.

     

    Open questlua_horse.cpp and add the following functions:

    	int horse_set_appearance(lua_State* L)
    	{
    		LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
    		if(!ch)
    			return 0;
    		if (!lua_isnumber(L, 1)) 
    		{
    			sys_err("wrong horse_appearance vnum");
    			return 0;
    		}
    		ch->SetHorseAppearance((DWORD)lua_tonumber(L, 1));
    		return 0;
    	}
    
    	int horse_get_appearance(lua_State* L)
    	{
    		LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
    		if(!ch)
    			return 0;
    		lua_pushnumber(L, ch->GetHorseAppearance());
    		return 1;
    	}
    

     

    At last we add the new funcions to the horse_functions table at the end of the file:

    			{ "set_appearance",		horse_set_appearance			},
    			{ "get_appearance",		horse_get_appearance			},
    

     

    That's all! Close questlua_horse.cpp and compile! :) Now we can use the following quest functions:

    horse.set_appearance(DWORD vnum) = changes the horse apperance to the vnum provided

    horse.get_apperance() = returns a lua number representing the current horse appearance vnum

     

     

    Have fun playing with it! :)

    • Metin2 Dev 17
    • Confused 3
    • Scream 1
    • Good 11
    • Love 27
  2. ccache also does some weird things on my VM. When I'm doing small changes, ccache will just ignore them (maybe because it thinks the files are unchanged or something). Even after cleaning, I was not able to compile a gamefile with changes. Only after waiting for a while or disabling ccache at compilation, the new gamefile worked as intended :)

     

    Also you'd note that people will have to change the Makefile, otherwise the source won't be compiled with ccache as far as I know, especially not if you're doing things like:

    CC = gcc49

     

    Instead, if you want to use ccache then, just use:

    CC = ccache gcc49

  3. Make sure that in cmd.h you have changed the SendNotice definition like this:

    extern void SendNotice(const char * c_pszBuf, bool IsBig = false);

    questlua_global.cpp refers to SendNotice() function in cmd.h which in your case may have the bool variable set to true and therefore displays it like it's a big notice which isn't the case :)

  4. No, belt_inventory does not cause this error.

    It's the inventory size clientside, not only the py-part but also the binary.

    Equipment is normally stored at the end of your normal inventory. The server now has 135 as the inventory size (45 more than the prior 90) so the equipment starts with index 136 there. But the client still thinks that the inventory size is just 90, so the equipment starts at 91 there. That's the mismatch you can see. When equipping something, the server will move the item to the proper index, so it's at 136+, not 91+ like the client has it :)

     

    In GameType.h change

    const DWORD c_Inventory_Page_Count = 2;

    to

    const DWORD c_Inventory_Page_Count = 3;

    and make sure you've recompiled everything after raising the inventory size serverside to 135. Then everything should work :)

  5. 1)

    The error is clearly a failed assertion.

    assertion means that you declare a statement that must be true, otherwise the game crashes. In your code, it's the assert(iSlot < SQL_MAX_NUM) part.

    So, the argument iSlot is bigger than SQL_MAX_NUM. SQL_MAX_NUM is defined in DBManager.h

    enum eSQL_SLOT
    {
        SQL_PLAYER,
        SQL_ACCOUNT,
    SQL_COMMON,
    SQL_HOTBACKUP,
        SQL_MAX_NUM,
    };
     
    I guess that should help you find the error. you can trace it back and fix it then ;)
     
     
    If you're using source, make sure that all the packets are in sync, that'll also fix the header mismatch errors ;) mainline_released serverside + novaline clientside does work (or one of those clean client sources) without those errors :)
    • Love 1
  6. The problem happens when you're doing something like a infinite loop. That's the point where the game can't update the tics because it's busy doing the loop over and over. The error you see is just a kinda security check to make sure the game instance doesn't eat up your whole resources and instead kills itself. So yeah, you better find that flaw, most likely it's a quest that's causing problems like this (I did the same mistake once too :P) :D

  7.  

     

    cmd_gm.cpp:1237: error: 'struct TPacketGGMonarchNotice' has no member named 'bIsBig'

     

     

    You must do the following:

     

    First open packet.h

    Search for SPacketGGNotice and add the following variable:

    bool bIsBig;

     

    Maybe you just missed it :)

  8. 0330 19:33:32667 ::   File "uiToolTip.py", line 1650, in __AppendMetinSlotInfo
     
    0330 19:33:32667 :: IndexError
    0330 19:33:32667 :: : 
    0330 19:33:32667 :: list index out of range
    0330 19:33:32667 :: 
     
     
    The error appears when you call an array with an index that's out of it's array bound. For example your array has size of 3 and you're calling it with index 10.
    I've looked up for the function where this happens:
     
    		for i in xrange(player.METIN_SOCKET_MAX_NUM):
    			self.__AppendMetinSlotInfo_AppendMetinSocketData(i, metinSlot[i])
    

    These are most likely the lines that cause the error. Note that our for loop goes until it hits METIN_SOCKET_MAX_NUM, which is increased to fit the new sockets. metinSlot is called with the current loop value - so that could be the culprit. metinSlot is extracted from the item data. So if the item data is still constructed with the old socket size, it could be the reason your code isn't running. Hope this helps :)

  9.  

    
    extern void BroadcastNotice(const char * c_pszBuf, bool IsBig = true);
    

    Why aren't you setting IsBig to true ??

     

     

    Because if you do that then all notices will be sent as big, even the notices sent with /n. We need the default value to be false, and only when we send notices with /b to tell the function that we want a big one.

     

    Quite correct. It's about defining it in the headers. We want to make it compatible with older function calls. There are several examples where the source calls our changed functions. If we'd change it to true, then every message would be in big notice style, not our small notice-style. Of course you can do so. But then you'd have to change your /n command to give "false" to your argument. So server messages and /b would be big notice and /n would be small notice. That's also a way you'd do it. It depends on your needs :) Feel free to adapt the source changes to your needs

  10. According to your error description I guess you missed a step or made a small mistake maybe. You told us that other players are getting the /b announces. So the only error is the bool variable. There something is not correct and that's why you don't see the /b board :) If you want, you can make screens of the changed functions and I can help you with that.

    • Love 1
  11. Thank you very much for sharing! :)

     

    You can also run the gamefile with gdb.

    This all requires that you're building your gamefile with debug support of course :) Otherwise backtracing can produce bad results.

     

    gdb game

    run

     

    Then you can reproduce the bug and see what happens. gdb can help a lot when fixing game crashes :)

  12. Good idea, Ken :) You can also replace

    std::auto_ptr<SQLMsg> pMsg(DBManager::Instance().DirectQuery("UPDATE player.player SET title = '%s' WHERE id = %u",c_szRankName,GetPlayerID()));

     

    with

     

    DBManager::Instance().Query("UPDATE player.player SET title = '%s' WHERE id = %u",c_szRankName,GetPlayerID());

     

    Since you aren't storing the result in a variable. It's better to not use DirectQuery unless you're selecting :)

    • Love 3
  13. Maybe your error is no problem with the source :)

     

    You can find a quest called game_option.quest

    Is it running on your server?

     

    quest game_option begin
    state start begin
    when login begin
    local val=0
    local msg = "Blocked function: "
     
    if pc.getqf("block_exchange") == 1 then
    msg = msg.."Trade "
    val = val + 1
    end
     
    if pc.getqf("block_guild_invite") == 1 then
    val = val + 4
    msg = msg.."Guild "
    end
     
    if pc.getqf("block_messenger_invite") == 1 then
    msg = msg.."Messenger "
    val = val + 16
    end
     
    if pc.getqf("block_party_invite") == 1 then
    msg = msg.."Party invitation "
    val = val + 2
    end
     
    if pc.getqf("block_party_request") == 1 then
    msg = msg.."Party Joining "
    val = val + 32
    end
     
    if pc.getqf("block_whisper") == 1 then
    msg = msg.."Short message "
    val = val + 8
    end
     
    if val != 0 then
    syschat(msg)
    end
     
    pc.send_block_mode(val)
    end
    end
    end
    
    • Love 2
  14.  

    You don't have to create a new topic for this :)

     

    If you need a source solution, I'll help you. Other than that you'll have to wait for someone to create a dif.

    Oh, and he can only create the dif if he gets the gamefile from you. The size differs in every rev so they can't speculate where the restrictions are in your gamefile ;)

    Humm, can you add me on skype ?

     

     

    Read my signature, I don't have that and it won't help you. I can't edit the gamefile, if you want me to help you, just tell me where the source is and I'll post you the changes needed to remove the protection :)

  15.  

    You don't have to create a new topic for this :)

     

    If you need a source solution, I'll help you. Other than that you'll have to wait for someone to create a dif.

    Oh, and he can only create the dif if he gets the gamefile from you. The size differs in every rev so they can't speculate where the restrictions are in your gamefile ;)

    Why you don't use you old account? 

     

     

    What old account? :D

    Oh and private questions should be asked by pm, we don't want to go OT here :)

  16. Don't blame him, he's maybe new to this :)

    Make sure you get to know your environment. The serverfiles consist of a dbcache, an auth-server and the cores (share directory is not important for this case). db and auth are usually in a folder called "common". The rest is splitted.

    Normally you have channel-directories like channel1, channel2, channel3, etc...

    If you just follow them you'll get the structure of your serverfile. Every channel consists of at least one core. Also there's one directory called game99, it's usually outside the channel directories because it's seperated and meant for special instances like wedding or OX.

    Feel free to experiment with them :)

     

    dbcache uses the db file. The db-file reads conf.txt, so that's not what you're looking for.

    Every gamefile uses CONFIG to read it's settings. There you go :)

    So remember: dbcache uses the db file, everything else is using a gamefile. And every gamefile needs a CONFIG to read it's settings. There just add the BIND_IP and you'd be ready to go :)

    • Love 1
  17. string.find does not return bool! :)

    It returns the position where it found the pattern. Also it returns nil if the pattern is not found within the string.

     

    Try it with that:

     

    if string.find(pc.get_name(), "[%s]") != nil then

     

    This should do the trick :)

     

    The ""..pc.get_name().."" has no use. You're just concatenating an empty string with the player name and then an empty string again. The result is the same as you'd get it when you just use pc.get_name() :)

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