Jump to content
metin2dev
Alina

[C++] horse appearance via database

Recommended Posts

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! :)

Edited by Alina
Fixed a typo
  • Like 13
  • Thanks 1

Share this post


Link to post
Share on other sites

Thank you, I love you Alina  :D  :wub:

 

Whew I have a fan! :D

Thanks for the nice reply! :)

  • Like 2

Share this post


Link to post
Share on other sites

The results are cached either way and something that needs to be accessed more than just once should be hold in RAM so the server can access it without any delays. That's why I chose to add it to the player points table :) Note that everytime you mount/unmount the vnum of your horse will be loaded again (as long as you're using a horse of course...^^)

Share this post


Link to post
Share on other sites

The questflag aren't cached ? I mean questflag directly on source code like that

DWORD   GetHorseAppearance()    { return GetQuestFlag("horse_manager.mount_vnum"); }

Share this post


Link to post
Share on other sites

That's why I said the results are cached either way. So it doesn't matter at all :)

I chose mysql cloumn because there may be other implementing ways. Maybe someone wants to add commands to this, the easiest way is with a player table holding the variable. That's why^^ Or maybe it was just more fun to code it that way. Chose what you prefer :D

Share this post


Link to post
Share on other sites

Sure I understand it :D it's more easy to fetch it also by a website or something. I just think my method is more "short" and also don't need create new quest command because the questflag exist already ^^

 

I don't want blame your work that is very nice, I just want explain my idea ^^

Share this post


Link to post
Share on other sites

Sorry for bumping an old thread, but I've a question. How I can make the different mounts follow me like the horse?

 

#edit: fixed by adding the mount vnums on char.cpp 

  • Like 1

Share this post


Link to post
Share on other sites
On 03/01/2018 at 2:19 AM, ZyuX said:

I have this bug: 

Did you add the horse appearance column to your player table ?

Share this post


Link to post
Share on other sites
Acum 3 ore, 3bd0 a spus:

Did you add the horse appearance column to your player table ?

Yes, I added it. Maybe not right querry?

Share this post


Link to post
Share on other sites
La 02.01.2018 la 17:19, ZyuX a spus:

I have this bug: 

I have the same bug

And i have another bug : i need to press 2 times the item so the mount to appear

Share this post


Link to post
Share on other sites
Acum 18 minute, darkess a spus:

I have the same bug

And i have another bug : i need to press 2 times the item so the mount to appear

For second bug, do txt like this:
 

71124    ނضյ    ITEM_QUEST    0    1    NONE    NONE    NONE        0    0    0    0    0    LIMIT_NONE    0    LIMIT_NONE    0    APPLY_NONE    0    APPLY_NONE    0    APPLY_NONE    0    1    0    0    0    0    0    0    0    0


 

Share this post


Link to post
Share on other sites

Hello,

I have got problem while compiling.

Quote

char_horse.cpp: In member function 'virtual DWORD CHARACTER::GetMyHorseVnum()':
char_horse.cpp:261: error: expected primary-expression before 'int'
char_horse.cpp:261: error: expected `)' before 'int'
char_horse.cpp:262: error: expected `)' before ';' token
gmake: *** [Makefile:131: OBJDIR/char_horse.o] Error 1

My Code:
 

DWORD CHARACTER::GetMyHorseVnum()
{
	
	int delta = 0;
	
	if((DWORD horse_looks = GetHorseAppearance()) > 0)
		return horse_looks;
	
	if (GetGuild())
	{
		++delta;

		if (GetGuild()->GetMasterPID() == GetPlayerID())
			++delta;
	}

	return c_aHorseStat[GetHorseLevel()].iNPCRace + delta;
}

Can somebody help me? :(

10 minutes ago, .Rise said:

Hello,

I have got problem while compiling.

My Code:
 


DWORD CHARACTER::GetMyHorseVnum()
{
	
	int delta = 0;
	
	if((DWORD horse_looks = GetHorseAppearance()) > 0)
		return horse_looks;
	
	if (GetGuild())
	{
		++delta;

		if (GetGuild()->GetMasterPID() == GetPlayerID())
			++delta;
	}

	return c_aHorseStat[GetHorseLevel()].iNPCRace + delta;
}

Can somebody help me? :(

SOLVED by:
 

DWORD CHARACTER::GetMyHorseVnum()
{
	
	int delta = 0;
	DWORD horse_looks;
	
	if((horse_looks = GetHorseAppearance()) > 0)
		return horse_looks;
	
	if (GetGuild())
	{
		++delta;

		if (GetGuild()->GetMasterPID() == GetPlayerID())
			++delta;
	}

	return c_aHorseStat[GetHorseLevel()].iNPCRace + delta;
}

 

Share this post


Link to post
Share on other sites
La 6/14/2017 la 22:00, z35 a spus:

Sorry for bumping an old thread, but I've a question. How I can make the different mounts follow me like the horse?

 

#edit: fixed by adding the mount vnums on char.cpp 

i have the same bug.. cand you give me the fix please?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×