Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Shaiya > Shaiya Private Server > Shaiya PServer Guides & Releases
You last visited: Today at 20:14

  • Please register to post and access all features, it's quick, easy and FREE!

 

[Tutorial] How to create Custom Monster AI

Reply
 
Old   #1
 
elite*gold: 10
Join Date: Jan 2012
Posts: 1,695
Received Thanks: 5,134
[Tutorial] How to create Custom Monster AI

Hello guys,
I planned on doing this for a while now, but I was delayed with a permanent ban, thanks to someone who recently left the Shaiya Section.
Anyway, here we are, a short tutorial on how to create custom monster AI, AI standing for artificial intelligence.

First of all, what does AI in Shaiya mean, and what can you do with it ?
  • Spawn multiple monsters when some event is triggered on a monster. For example: When a mob reaches 80% of its full HP, you can make it duplicate itself. You can also choose where a new mob will be spawned after the event is triggered, which makes this custom AI much more flexible than what you can do in Obelisk.ini
  • Unlock portals.
  • Make the mob affected by this AI to change the types of attacks or use other attack skills.
  • Make monsters talk.
  • Delete monsters.
  • More cool things that you might wanna research by yourself.

Such a thing is seen in game only on 2 maps. It has nothing to do with the maps, except for the fact that those maps are Caelum Sacra F1(light), Caelum Sacra F1(fury) and Caelum Sacra F2, and as you probably already know, the monsters affected by custom AI, which we're going to be guiding by in this tutorial, are all forms of Dios Exiel and his 4 guards, Eternel, Gargadel, Huistaton and Luhiel.

Let's get started. The files that you're going to need are stored on the server side, obviously, in the PSM_Client\Bin\Data\Lua folder.
I think the best way to understand this is by applying a custom AI to a monster that doesn't have one yet. All you have to do is follow along, and do exactly as the tutorial says. If you do everything right, you will most likely understand how this works.
Let's say we take Dentatus and apply a custom AI to it that does the following:
  • Part 1 : When you start attacking it, it will insult you.
  • Part 2 : When its HP reaches 75%, Secreta will spawn and Dentatus will say something related to that.
  • Part 3 : When its HP reaches 50%, Lumen will spawn and Dentatus will say something related to that.
  • Part 4 : When its HP reaches 25%, Ales will spawn, Dentatus will say something related to that and it will also start using Death Breath.
  • Part 5 : When its about to die, Dentatus will totally curse you and promise to take revenge.
If you never messed with the .lua files, then the highest custom AI you have is surely 118. Take any .lua file from that folder, copy it and paste it in the same folder. Rename it to 119.lua and open it in notepad.

The first line says something like :
Code:
-- ДАПл зЕу єёЅє 2Вч_єРЅЕ јТИЇЗвАь ёуЅєЕН_ID-2470 AI 117.Lua  ver.090113
The 2 numbers I underlined stand for the ID of the mob you want the AI to be applied on, and for the number of the AI, so basically it must look like this:
Code:
-- ДАПл зЕу єёЅє 2Вч_єРЅЕ јТИЇЗвАь ёуЅєЕН_ID-2821 AI 119.Lua  ver.090113
The following line respresents the initialization of the custom AI:
Code:
Mob = LuaMob(CMob)
These 3 lines represent the initialization of 3 variables:
Code:
dwNextCreateTime = 0
bMobSay	= 0
bMobCreate = 0
These lines are the function declarations:
Code:
function Init()
end

function OnAttacked( dwTime, dwCharID )
end

function OnAttackable( dwTime, dwCharID )
end

function OnNormalReset( dwTime )
end

function OnDeath( dwTime, dwAttackedCount )
end

function OnReturnHome( dwTime, dwAttackedCount )
end

function OnMoveEnd( dwTime )
end

function WhileCombat( dwTime, dwHPPercent, dwAttackedCount )
end

For what we set out to do we could have used more of the above functions, but I decided to put all the code in the last one, which is function WhileCombat.

Part 1:

We need to make Dentatus insult us. Everything a monster speaks is located on the client side, in sysmsg-uni.txt. Go to the bottom, and make a new line. For this tutorial we'll use line count from 12001 on.
It should look like:
Code:
12001     "My name is Dentatus and yo mama's so fat that she's stuck at the login page."
Code:
if ( dwHPPercent >= 95 ) then
if ( bMobSay < 1) then
Mob:LuaSayByIndex ( 12001, 200.0 )
bMobSay = bMobSay + 1
end
end
Since I decided to store all the things we're going to do in the WhileCombat function, we had to run a check on the monster's health. Normally you cannot kill Dentatus in 1 hit, so the first line checks if Dentatus's HP is at 95% or above, which surely has to be. The second line checks the variable bMobSay, which is a counter for how many times the monster has spoken. The next, third line is the one that makes the monster actually speak, the first parameter stands for the index of the string it needs to display, taken from the sysmsg-uni.txt. The forth line is where we increment the bMobStay variable, which again, is a counter for how many times the monster has spoken. The AI will still work without it, but as you saw our second line, we need to keep track of the amount of times the monster has spoken.

Part 2:

We need to make it so when Dentatus reaches 75%, Secreta will spawn and Dentatus will say something related to that.
The text goes inside the WhileCombat function, below the one we wrote for the first part of our objective.
Code:
if ( dwHPPercent <= 75 ) then
if ( bMobSay < 2) then
Mob:LuaSayByIndex ( 12002, 200.0 )
bMobSay = bMobSay + 1
end
Mob:LuaCreateMob ( 2803, 1, 0.0, 0.0 )
end
As you see, there's just one new function that is actually very easy to understand, but I'll still explain it shortly. The LuaCreateMob function is the one responsible for a new spawn. The 4 parameters stand for MobID to be spawned, how many of those mobs to be spawned and the coordinates on the X and the Z axises where to spawn the specified amount of mobs of the specified MobID. If the coordinates are 0.0 it will spawn in the same point where the monster whom the AI is applied to.

Part 3 shouldn't be hard to complete on your own, as it is very similar to Part 2.

Part 4:

We need to make it so when Dentatus's HP reaches 25%, Ales will spawn, Dentatus will say something related to that and it will also start using Death Breath.
Code:
if ( dwHPPercent <= 25 ) then
if ( bMobSay < 4) then
Mob:LuaSayByIndex ( 12004, 200.0 )
bMobSay = bMobSay + 1
end
Mob:LuaCreateMob ( 2785, 1, 0.0, 0.0 )
Mob:LuaAttackAI ( 173 )
end
The function that is still new to you is LuaAttackAI. It enables the use of another skill, the parameter representing the SkillID of the skill you want the monster to use, taken from the NpcSkill.SData. NpcSkill.SData is the file located in the client side, in the Data\Monster folder. If you want to be able to open it with Shaiya Studio, rename it to Skill.SData. There you can find all the skills available for the monsters to use. The equivalent skills server sided are located in the database, inside PS_GameDefs.dbo.Skills, with SkillLevel = 100.

The fifth part is just like part 2 and 3, so you shouldn't have any problem to write that.

Before testing, don't forget to assign the AI to the mob, in this case Dentatus:
Code:
UPDATE PS_GameDefs.dbo.Mobs
SET AI = 119
WHERE MobID = 2821
A server restart is required to make the changes apply.

P.S. I wrote this tutorial from college, on a PC that was built in the previous century, so everything comes from my head. I've previously done that on my test server, and it was successful. If this doesn't work as expected, I'll look into it more when I get home.



nubness is offline  
Thanks
57 Users
Old   #2
 
elite*gold: 0
Join Date: Oct 2012
Posts: 145
Received Thanks: 196
Lol, just found the way of this 1 week ago but still a nice release, i diden't understand everything on the lua files, now i think i will be abble to do some nice things ^^


infinite59 is offline  
Thanks
3 Users
Old   #3
 
elite*gold: 0
Join Date: Dec 2010
Posts: 660
Received Thanks: 2,975
Thanks nubness for this tuto. I was also working on this but miss time to finalize something.

Your tuto explains very well the use by the ps_game service of these Lua scripts as well as some of the actions (verbs) that can be used.

For those who wish to go further, looking at ps_game with HxD give some info.

first, we find a copyright:

"Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
"Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes
"URL: www.lua.org"

The Lua is an open source scripting language and the lua.org website provides the full documentation for language syntax and capabilities.

we also find the definition of a class 'Mob' with the following verbs (methobs):
Code:
LuaAttackAI
LuaAttackOrderSurroundMob
LuaCreateMob
LuaDeleteMob
LuaFixedMove
LuaGetMinAggro
LuaGetMobHP
LuaGetMobCountByType
LuaGetMobPos
LuaGetNumberAggro
LuaGetName
LuaRecallUser
LuaRecover
LuaResetAggro
LuaSay
LuaSayByVoice
LuaSayByIndex
LuaSetHoldPosion
LuaSetOnlyLuaAttack
LuaSetReTargetingTerm
LuaSetTarget
LuaSetUnBeatable
LuaUpdateInsZonePortal
for some of them we have samples of use in the existing scripts. for others we will have to discover the parameters with tries/failures.

thanks to post your discoveries.


Note:
Quote:
NpcSkill.SData is the file located in the client side, in the Data\Monster folder. If you want to be able to open it with Shaiya Studio, rename it to Skill.SData
or select it in the standard open file dialog and make sure the file type "Skills File" is selected in the file-types combo box just under the filename input field.
castor4878 is offline  
Thanks
19 Users
Old   #4
 
elite*gold: 0
Join Date: Jul 2010
Posts: 374
Received Thanks: 378
Thanks
Been using it lately but didn't know LuaAttackAI() was to trigger mob skills. That's really interesting. This mean now we could make bosses that randomly use different kind of skills on every battle?


Another commands:

-- make mob non-attackable
Mob:LuaSetUnBeatable (1)

-- make mob attackable again
Mob:LuaSetUnBeatable (0)

-- make mob walks to X, Y (ignoring player)
-- (don't know what the 1 is for)
Mob:LuaFixedMove( 1, X , Y )


And there's:

Mob:LuaUpdateInsZonePortal ( 1001, 0 )

Wich I asume enable (and may be disable) special portals?
Do you know how it works?


sominus is offline  
Thanks
6 Users
Old   #5
 
elite*gold: 10
Join Date: Jan 2012
Posts: 1,695
Received Thanks: 5,134
First of all, I didn't include all the available functions:
  • LuaUpdateInsZonePortal
  • LuaGetMobHP
  • LuaGetMobPos
  • LuaRecover
  • LuaSayByVoice
  • LuaSayByIndex
  • LuaRecallUser
  • LuaFixedMove
  • LuaDeleteMob
  • LuaResetAggro
  • LuaSetUnBeatable
  • LuaGetMobCountByType
  • LuaSetHoldPosion
  • LuaSetOnlyLuaAttack
  • LuaGetNumberAggro
  • LuaGetMinAggro
  • LuaSetReTargetingTerm
  • LuaAttackOrderSurroundMob
  • LuaSetTarget
  • LuaAttackAI
  • LuaCreateMob
  • LuaGetName
  • LuaSay

I myself haven't tried them all, not sure who to blame for that, grandma, or maybe Hitler ? I think I'll blame Chuck Norris.

LuaUpdateInsZonePortal is actually used by the 4 Dios Exiel guards, Eternel, Gargadel, Huistaton and Luhiel, their AI's being 111,112,113 and 114. Its syntax is easy to understand.

There's more functions that aren't used though, but by their name I have to assume they are very powerful.
For example LuaRecallUser, I believe this function could summon a player to a specific location. Episode 5 server files have something like that. I never had those files, but as far as I know, in OS, ROTCO/Dimension's Crack dungeon auto summons players to the next room after the boss in the current room died.

I got all the functions by looking for one of them inside the ps_game.exe in hex. They're all located close to each other.

I'm not an expert in this, nor am I the best, and it also doesn't take much brain.exe to understand how the custom monster AI works, so I'm sure people will be able to do much more after reading this tutorial.

EDIT : Weird that I didn't see castor's post. Sorry for repeating the same information. And thank you castor for your input. It is indeed useful, as everything that comes from you.
nubness is offline  
Thanks
10 Users
Old   #6
 
elite*gold: 0
Join Date: Jul 2010
Posts: 374
Received Thanks: 378
Don't know if this was already explained before:

To avoid restarting the server everytime you change something in the .lua file, use the command /aiset [MobID] [lua index]
Example:
Code:
/aiset 3232 152
That will reload 152.lua on mob 3232, so you just /mmake the mob again and it will have the new behavior, without reloging the client or restarting the server.

The server will show a msg like this:
Code:
# /aiset 3232 152
cmd aiset[3232:100->152] ok
It means it was using 100.lua and now it's using 152.lua. Of course we can reload the same lua.

As you know, this command goes in the 'game' service:

PSMServer_Mgr > GameGroups01 > Game > (right click, choose 'Command')
Code:
http://img407.imageshack.us/img407/898/shaiyaaiset1.jpg
Updated:
Make the mob say a custom string, or the content of a var
Code:
Mob:LuaSay ('any string' or local var, <distance>)
Example:
Mob:LuaSay ('hello world', 20.0)
Example:
Mob:LuaSay (dwTime, 20.0)

//The mob will say that, and it will be heard only around 20 meters from the mob. 
//Useful to test var contents.

//You can also concatenate (in Lua we use two dots to concatenate '..'):
Example:
Mob:LuaSay ('current time is: ' .. dwTime, 20.0)
Make the mob play a wav file:
Code:
Mob:LuaSayByVoice('myfile.wav', <distance>)
Example:
Mob:LuaSayByVoice('evil_laugh.wav', 25.0)

//The mob will 'play' the file evil_laugh.wav, and will be heard around 25
//meters around him, when you walk away from the mob, the sound starts to
//fade-off with the distance. 
//The sound file goes in: Data/Sound
Get current mob HP % left (in percent, with 3 decimals):
Code:
//declare some variable at begining of the file
dwTest = 0

//put this inside [I][B]WhileCombat[/B][/I] function
dwTest = Mob:LuaGetMobHP()

//then you can do this, to test:
Mob:LuaSay('My HP% left is: .. dwTest, 100.0)
LuaGetMinAggro()
//it seems to return the CharID of the player with aggro (I've tested alone so I dont know what happens when more players are involved)
sominus is offline  
Thanks
23 Users
Old   #7
 
elite*gold: 10
Join Date: Jan 2012
Posts: 1,695
Received Thanks: 5,134

That's amazing man, your contribution to this is huge. Glad to see that someone has time for such tests and is sharing their discoveries with the community.

About aggro, a mob can only have aggro on one character, normally the one with higher REC/defense, and that has been hitting the mob for >= time than other characters.

Thanks again, man. Great job. I wish you further luck with your tests, if you're going to keep on doing them.
nubness is offline  
Thanks
7 Users
Old   #8
 
elite*gold: 0
Join Date: Jul 2010
Posts: 374
Received Thanks: 378
myvar = LuaGetMinAggro() //stores player's CharID (it works)
othervar = LuaGetName(any_charid) //stores that player's name (it works)

I've tried using LuaGetMinAggro() to get the CharID of the current player with aggro, and then using LuaGetName(var_with_charid) to get the actual nick of that player (e.g. To make the boss talk to that player by it's name)
But can't make it work. I dont get any errors, it just doesn't say the nick.

Im not good at coding so i was thinking may be the error is because charid uses a int
and charname uses a string?

Update:
Found the error, I was missing the 'Mob:' part before the function name. (thanks infinite59)
sominus is offline  
Thanks
8 Users
Old   #9
 
elite*gold: 0
Join Date: Oct 2012
Posts: 145
Received Thanks: 196
Quote:
Originally Posted by sominus View Post
myvar = LuaGetMinAggro() //stores player's CharID (it works)
othervar = LuaGetName(any_charid) //stores that player's name (it works)

I've tried using LuaGetMinAggro() to get the CharID of the current player with aggro, and then using LuaGetName(var_with_charid) to get the actual nick of that player (e.g. To make the boss talk to that player by it's name)
But can't make it work. I dont get any errors, it just doesn't say the nick.

Im not good at coding so i was thinking may be the error is because charid uses a int
and charname uses a string?
Just tested it, exemple:
Code:
	bCharID = Mob:LuaGetMinAggro()
	bCharName = Mob:LuaGetName( bCharID )
	Mob:LuaSay(  'test ' .. bCharName .. ', are you afraid to die?', 20.0 )
If your char is named 'Toony', boss will say 'test Toony, are you afraid to die?'

Edit: Sometimes, it will not tell the name, but most of time it work.
infinite59 is offline  
Thanks
7 Users
Old   #10
 
elite*gold: 0
Join Date: Jun 2012
Posts: 71
Received Thanks: 76
In fact, in ep 5 features even more is all the functions that are in the ep 5. I took them out of the ep 5 ps_gamewar.exe that is not protected.
Code:
LuaMobCommand
LuaUseSkillAtMob
LuaGetMobUID
LuaUpdateInsZonePortal
LuaGetMobHP
LuaGetMobPos
LuaRecover
LuaSayByVoice
LuaSayByIndex
LuaRecallUser
LuaFixedMove
LuaDeleteMob
LuaResetAggro
LuaSetUnBeatable
LuaGetMobCountByType
LuaSetHoldPosion
LuaSetOnlyLuaAttack
LuaGetNumberAggro
LuaGetMinAggro
LuaSetReTargetingTerm
LuaAttackOrderSurroundMob
LuaSetTarget
LuaAttackAI
LuaCreateMob
LuaGetName
LuaSay
WhileCombat
OnMoveEnd
OnAttacked
OnAttackable
OnNormalReset
OnDeath
OnReturnHome
And ps_gamewar
Sorry for my english
Attached Files
File Type: zip ps_gamewar.zip (677.4 KB, 124 views)
Призрак урана is offline  
Thanks
3 Users
Old   #11
 
elite*gold: 576
Join Date: Mar 2011
Posts: 348
Received Thanks: 941
First, thank you nubness for this useful post and thanks to those who share their discoveries.
About the LuaGetMinAggro function, it seems not to always store the char ID because the process of targeting a specific char might get interrupted by attacking the mob. If I'm in a combat with the mob without attacking it, it continuously store the char ID. You could save the chars' ID in a variable and check if it's greater than 0. If it is, say something related to the player by calling his name and it the variable is 0 say something more general.
Example:
Code:
if dwHPPercent <= 75 and bMobSay < 1 then
	bMobSay = bMobSay + 1
	CharID = Mob:LuaGetMinAggro()

	if CharID > 0 then
		CharName = Mob:LuaGetName(CharID)
		Mob:LuaSay ('Nice to meet you, '..CharName,20)
	else
		Mob:LuaSay ('Hello everyone.',20)
	end
end
I tested the LuaRecover function and it obviously cures the mob. It requires two parameters, the first specifies the delay it takes to cure. I'm not sure about this but the greater the value is the more time the mob needs to cure if I remember right. The second parameter specifies the HP it cures in percent.
Example:
Code:
if dwHPPercent <= 50 then
	Mob:LuaSay ('Stupid folks, you can not kill me!',50)
	Mob:LuaRecover (1,100)
end
Philipp_ is offline  
Thanks
13 Users
Old   #12
 
elite*gold: 0
Join Date: Jul 2010
Posts: 374
Received Thanks: 378
Nice!

Now, what I can't find (I tested alone, with 2 accounts, no other players around), is:
LuaGetMinAggro: does it target the player with 'minimal' aggro? Or minimal defense/rec?

Or it simply target the player that has the greater aggro as usual?

(thing is, I wanna make a boss switch targets based on certains variables, to avoid those "i've linked myself full of life lapis so the boss won't attack anybody else in the raid" people.)
sominus is offline  
Thanks
1 User
Old   #13
 
elite*gold: 0
Join Date: Oct 2012
Posts: 145
Received Thanks: 196
Quote:
Originally Posted by Philipp_ View Post
First, thank you nubness for this useful post and thanks to those who share their discoveries.
About the LuaGetMinAggro function, it seems not to always store the char ID because the process of targeting a specific char might get interrupted by attacking the mob. If I'm in a combat with the mob without attacking it, it continuously store the char ID. You could save the chars' ID in a variable and check if it's greater than 0. If it is, say something related to the player by calling his name and it the variable is 0 say something more general.
Example:
Code:
if dwHPPercent <= 75 and bMobSay < 1 then
	bMobSay = bMobSay + 1
	CharID = Mob:LuaGetMinAggro()

	if CharID > 0 then
		CharName = Mob:LuaGetName(CharID)
		Mob:LuaSay ('Nice to meet you, '..CharName,20)
	else
		Mob:LuaSay ('Hello everyone.',20)
	end
end
I tryed this:
Code:
bCharID = 0
while ( bCharID == 0 ) do
bCharID = Mob:LuaGetMinAggro()
end
bCharName = Mob:LuaGetName(bCharID)
Mob:LuaSay ('Your CharName is: ' .. bCharName, 500)
This way the boss will in all cases find the CharID (i made 10 tests and all worked)
Quote:
Originally Posted by Philipp_ View Post
I tested the LuaRecover function and it obviously cures the mob. It requires two parameters, the first specifies the delay it takes to cure. I'm not sure about this but the greater the value is the more time the mob needs to cure if I remember right. The second parameter specifies the HP it cures in percent.
Example:
Code:
if dwHPPercent <= 50 then
	Mob:LuaSay ('Stupid folks, you can not kill me!',50)
	Mob:LuaRecover (1,100)
end
I tested by setting Mob:LuaRecover(10,100)
and the delay diden't change for me.
infinite59 is offline  
Thanks
3 Users
Old   #14
 
elite*gold: 0
Join Date: May 2012
Posts: 58
Received Thanks: 17
Gives an function that call to all Member like server notice?
Coolie_85 is offline  
Old   #15
 
elite*gold: 10
Join Date: Jan 2012
Posts: 1,695
Received Thanks: 5,134
Quote:
Originally Posted by Coolie_85 View Post
Gives an function that call to all Member like server notice?
Nope, you cannot make a server-wide notice using the monster AI scripts.


nubness is offline  
Thanks
1 User
Reply

Tags
ai, custom, monster, shaiya



« Previous Thread | Next Thread »

Similar Threads
[HELP] How do i create a custom interface?
Hey guys , Im just wondering if you could tell me or link me a guide of how to create a custom interface for eudemons online because i have no idea...
7 Replies - EO PServer Hosting
How do I create a custom server.dat?
Now I know I will probably be flamed, but I have searched through google and through the forums a plethora of times and have not found a straight...
2 Replies - CO2 PServer - Discussions / Questions
How to create Custom Quests?
Just as the title says im looking into making some custom quests with custom rewards to add something different for the players. What i wanna know...
3 Replies - Dekaron Private Server
create a website Custom
Hello, demo : http://img84.imageshack.us/img84/6397/testnp.pnghttp://img695.imageshack.us/img695/84/test2jh.png Good luck.
11 Replies - Shaiya PServer Development
Create monster
To generate a monster he is born only once, when dead not coming back?
5 Replies - EO PServer Hosting



All times are GMT +2. The time now is 20:14.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Abuse
Copyright ©2017 elitepvpers All Rights Reserved.