the SERVER scripting thread

Moderator: EUO Moderators

Post Reply
User avatar
LordMortiferus
MACRO > me
Posts: 872
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Post by LordMortiferus »

Here is a rough list of the custom avatar heads:

Code: Select all

0xfe4 - woody woodpecker
0xfe5 - lion
0xfe6 - female skeleton
0xfe7 - dianoga
0xfe8 - mage
0xfe9 - strange creature
0xfea - female
0xfeb - blue hair
0xfec - undead lord
0xfed - skeleton
0xfee - phantom
0xfef - Estorath
0xff0 - cowboy
0xff1 - draconian
0xff2 - shadow lord
0xff3 - troll priest
0xff4 - ettin
0xff5 - deamon
0xff6 - mongbat
0xff7 - moth
0xff8 - mino
0xff9 - dwarf
0xffa - knight
0xffb - shadow orc
0xffc - king
0xffd - guard
0xffe - alien
0xfff - monochrome head
Usage is 0x8XXXYYY with XXX the hexcode of the head and YYY the avatar code. 0x8000000 superimposes the head over the avatar.
User avatar
LordMortiferus
MACRO > me
Posts: 872
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Post by LordMortiferus »

This is a how to make tinted and named items tutorial.

Basic item code is 0xAYYY, with A the tint value and YYY the Item code. This works for tints between 0x0 and 0xf.
2 or 3 digit material tints work different (refer to materials.txt in dat-folder for a complete list)
With a material code 0xBA the item code would be 0xAYYY.B
With a material code 0xCBA the item code would be 0xAYYY.CB

Examples:
2-digits:
Mithril has a material code of 0x10. A mithril item has the code 0x0YYY.1 or just 0xYYY.1
Runed has a material code of 0x11. A runed item has the code 0x1YYY.1

3-digits (mythic)
Felmythic has a material code of 0x200. A felmythic item has the code 0x0YYY.20 or just 0xYYY.20
Iron (0x2) Felmythic (0x200) has a material code of 0x202. An iron felmythic item has the code 0x2YYY.20
Runed (0x11) Felmythic (0x200) has a material code of 0x211. A runed felmythic item has the code 0x1YYY.21

To name an Item use 0xYYY..NAME (note the 2 dots)
E.g. void (0x2a) felmythic (0x200) claymore (0x15) named Morty would be 0xa015.22.Morty

I hope that was kinda understandable.
@Heikki: can you add this to your "ItemHelper"?
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the scripting thread

Post by Kynt »

Been meddling with npc conversation scripts. What I've found so far:

You can make a function run every time a player replies to an npc by doing m.chat_func = <name>, where name is a string of the target function's name (you would do this on the npc spawn script).
This target function receives the following parameters: f(npc, first_word, full_msg), where npc is a pointer to the speaking npc, first_word is the first word of the player's spoken phrase to the npc in lowercase, and full_msg is the complete phrase given to npc, case sensitive.
The return value for this function is a string that determines the npc's answer to the player.

This is an example of how I've been using chat_func:

Code: Select all

function npc_george_chat(npc, first_word)
	local word = string.sub(first_word, 1, 4)
	
	if word == "balr" then --Branch: balron ; Branches into: pits
		return "Very powerful demonspawn they are! Be careful if you ever find one in your journey. Have you ever been to the pits below Minotaur Halls?"
		
	elseif word == "pits" then --Branch: pits
		return "A treacherous place, deep down in these pits you can find yourself surrounded by these balrons!"
	end
	
	return "I cannot help you with that."
end
In this function, an npc will respond to the words "balron" and "pits". As you can see, I simulated EUO's conversation system where only the first 4 letters of the spoken word matter by using string.sub. Those "branch" comments aren't really necessary but they help me in case the conversations get too convoluted.

Another thing I've found is that you can highlight those keywords by doing this (running these once at map load is enough):

Code: Select all

convos:add_line("George", Item(0), "balron", "") --balron
convos:add_line("George", Item(0), "pits", "") --pits
This is the add_line function from the api, for reference:

Code: Select all

class Conversations  
{
public:
   void add_line(const string & name, const Item & item, const string & keyword, const string & reply);
};
I might be reinventing the square wheel here but it has worked for me so far!
The one problem I have is I don't know how to get a pointer to the player speaking to the npc, thus I can't use player name in npc speech or do stuff involving the player (e.g. give/take/check items, heal, etc).
Chedich
on lolpatrol
Posts: 254
Joined: Wed Jan 14, 2004 12:51 am

Re: the scripting thread

Post by Chedich »

Kynt wrote: This is an example of how I've been using chat_func:

Code: Select all

function npc_george_chat(npc, first_word)
	local word = string.sub(first_word, 1, 4)
	
	if word == "balr" then --Branch: balron ; Branches into: pits
		return "Very powerful demonspawn they are! Be careful if you ever find one in your journey. Have you ever been to the pits below Minotaur Halls?"
		
	elseif word == "pits" then --Branch: pits
		return "A treacherous place, deep down in these pits you can find yourself surrounded by these balrons!"
	end
	
	return "I cannot help you with that."
end
I might be reinventing the square wheel here but it has worked for me so far!
The one problem I have is I don't know how to get a pointer to the player speaking to the npc, thus I can't use player name in npc speech or do stuff involving the player (e.g. give/take/check items, heal, etc).
Have you tried using 'target = get_sent_ptr(npc.target_id)' within the chat function? Dunno if it works, just an idea.
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the scripting thread

Post by Kynt »

I have tried returning many of the monster class variables but none seem to point towards the player talking to it (including target_id).
Last edited by Kynt on Wed Apr 11, 2018 5:08 am, edited 1 time in total.
Chedich
on lolpatrol
Posts: 254
Joined: Wed Jan 14, 2004 12:51 am

Re: the scripting thread

Post by Chedich »

Another idea: In case the item in convos:add_line() is an item that is given(and not an item that's required for the line to show up) one could give out an item to the person that's talking to the npc and then check the surrounding tiles for players with that item. However I'm guessing the item argument is for a required item. :/
User avatar
LordMortiferus
MACRO > me
Posts: 872
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Post by LordMortiferus »

It seems that a function is called from within the conversations in case you want to check if the player has an item, enough gold, a certain skill etc.:

Code: Select all

function npc_chat (m, id)
  p=get_player_ptr(id) -- here you get the pointer for the player
  if p.whatsoever == something then
    send_npc_reply(id,"Text",npc)
  end
end
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the scripting thread

Post by Kynt »

Interesting, I'll do some experimenting with it later, pointer to player is what I needed after all.
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the scripting thread

Post by Kynt »

Hmm, I've been trying different ways to call that function (npc_chat) but I have no idea when or from where it's called.

EDIT: I did notice that causing a bug in the npc's "chat_func" function makes the message "script_npc_chat crash caused by func=<function name>" pop in the server logs. Perhaps this script is hardcoded into the server?
User avatar
LordMortiferus
MACRO > me
Posts: 872
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Post by LordMortiferus »

In Lua you can trigger a script using the following:

Code: Select all

convos:add_line("George", Item(0), "script", "TRIGGERSCRIPT functionname")
Item is a quest item or any other item that is needed to trigger a specific conversation.
I hope this works for you.
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the scripting thread

Post by Kynt »

LordMortiferus wrote:In Lua you can trigger a script using the following:

Code: Select all

convos:add_line("George", Item(0), "script", "TRIGGERSCRIPT functionname")
Item is a quest item or any other item that is needed to trigger a specific conversation.
I hope this works for you.
Oh, didn't know about the TRIGGERSCRIPT thing. Now it works! However this can't be used along with chat_func (since it doesn't trigger the convo reply), but being able to attach functions to keywords works well enough for me. Thanks!
User avatar
eggmceye
hello
Posts: 10577
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia
Contact:

Re: the scripting thread

Post by eggmceye »

maybe I should document this stuff properly one day ... and I just went back to the OP which hasn't been updated in 10 years and doesn't even have a link to the latest api :fp:

with conversations, the flow chart sorta works like this (after t-dir):

1) match keyword to quest: if found do quest stuff (quests are their own system completely, outside of lua)
2) else if npc has chat_func not "" then call it
3) else look for keyword in the conversation txt files
... convo files can call lua scripts using TRIGGERSCRIPT and quests with TRIGGERQUEST

the original idea of using chat_func was for a bot to talk like a player: that was used a couple of times in past but is not now. it is now only used for edgar's ghost for some reason! and that is not a smart response, so unsure why it is used there. maybe because he is neutral? I can't remember.

convos:add_line is for adding lines dynamically to conversation txt files, and indeed, since only this year, SAVES the txt file ! (in the past it was for the sandy valley npcs that had all the same keyword/replys) .... so currently it's not really meant to be used by lua, or at least I haven't thought of modern uses for it in lua. I made this change so I could edit npc convos ingame as a dm, rather than using spreadsheets. so currently unsure of what you guys want/need and how to implement that.
Kynt wrote:I have tried returning many of the monster class variables but none seem to point towards the player talking to it (including target_id).
m.chat_func .... no player id is passed to it - which having read this thread is now an obvious oversight! either I set target_id in the engine ( which could but probably wont break something ) or just add id to the func call, which is probably the proper way to do it.

morty's solution of convos:add_line("George", Item(0), "script", "TRIGGERSCRIPT functionname") is probably the gold standard for scripted replies, now that I think about it. I jsut did a count and it's used 132 times in euo :) stuff like race change, anything in the shoppe, converting to vamp, kicking the cat, heaps of stuff.
User avatar
eggmceye
hello
Posts: 10577
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia
Contact:

Re: the scripting thread

Post by eggmceye »

I just updated the top 3 OPs, separating them into intro, server->lua and API :deek:

also separated out the auxbox posts into their own thread, and merged another api thread I found into this one

auxbox posts get their own forum now :aus:
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the SERVER scripting thread

Post by Kynt »

I agree convos:add_line is a good solution since it also includes the normal npc responses like job, time, name, etc. unlike chat_func (unless it floods the conversations file in case of being called repeatedly, as its name implies?). Being able to attach scripts to keywords makes it pretty flexible.
Avoid globals attached to monsters ... because if your map becomes instanced then those globals do not become instanced. "variables attached to mobs" is not handled very well: update this post oneday with practical tips and pointers.
Pretty curious as to what a good alternative to these are since I keep using globals!
User avatar
eggmceye
hello
Posts: 10577
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia
Contact:

Re: the SERVER scripting thread

Post by eggmceye »

actually I need to clarify, the best thing about mort's convos:add_line is not the add_line but the ref to TRIGGERSCRIPT

I hardly use add_line, but use TRIGGERSCRIPT all the time, and use that directly in sdat/conversations/yourconversationfile.txt

add_line now simply adds line to sdat/conversations/whatever.txt (and there are many files in that directory)
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the SERVER scripting thread

Post by Kynt »

But when it comes to map making, is it best to use add_line for the whole conversation in the map script or make a conversation file with the NPC stuff in it, then send it to you? (thing is I'm not sure how this file is used as I have no example to go by)
So far I've been using add_line and the NPC works correctly.
User avatar
LordMortiferus
MACRO > me
Posts: 872
Joined: Tue Dec 01, 2009 10:23 pm

Re: the SERVER scripting thread

Post by LordMortiferus »

eggmceye wrote:actually I need to clarify, the best thing about mort's convos:add_line is not the add_line but the ref to TRIGGERSCRIPT

I hardly use add_line, but use TRIGGERSCRIPT all the time, and use that directly in sdat/conversations/yourconversationfile.txt

add_line now simply adds line to sdat/conversations/whatever.txt (and there are many files in that directory)
**
The structure of the text file is similar to the add_line command. Example:
Anonymous 0 job I work at a big company.
Anonymous 0 "time, date" It is 10 minutes past 3 on April 12th.
Anonymous 2bf00127 join TRIGGERSCRIPT join_anonymous
#
Balron 0 kill I kill for fun.
#
The second line is triggered by either "time" or "date" and the third line will trigger a script if the player has a certain item. Max uses tab stops between the arguments - use this as well for better readability.

Here is how yes/no question probably work and non conversation bits:

Code: Select all

NPC	0	smile	NPC smiles.:: I love you.
NPC	0	convert	"PROMPT::Are you absolutely sure you wish to convert (yes/no)"
NPC	0	conv-yes	TRIGGERSCRIPT convert_to_something
NPC	0	conv-no	Maybe later then!
PROMPT will need a yes/no input. The first 4 letters of the trigger word plus the yes/no will trigger the next line/script (I am taking a guess here). Like in the example above some conversation are in quotations marks and some are not - which I cannot explain right now.
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the SERVER scripting thread

Post by Kynt »

Got it to work with the conversation file. Also good to know about the prompts. Thanks!
User avatar
Kynt
LAUGHING OUT LOUD LIKE A MORON
Posts: 61
Joined: Wed Feb 18, 2015 9:04 am

Re: the SERVER scripting thread

Post by Kynt »

I'm curious about how instanced maps works, like heroic or epic. I'm guessing the entrance portal to a heroic instance creates an instance through script or a special portal setting.
When it comes to stronger mobs though (e.g. 3x, 5x), do spawners get attached to some scaling script or is it automated for all spawned monsters somehow?

Actually not sure if this is a map maker's business or egg's but whatever I can do to help a map get instanced I'll try!

EDIT: regarding global vars and instances, I already have an idea for separating instance variables from globals but I'd need to test it first if possible.
User avatar
eggmceye
hello
Posts: 10577
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia
Contact:

Re: the SERVER scripting thread

Post by eggmceye »

firstly, spawner scripts are only called by instances.

if you have a prt, set the val (tgt lvl number) is negative (which tells server to make it an instance) - and you put the name of the spawner function in the text field, and that func is called for every mob spawned. if you use a lvl, either put item=-1 (0xffffffff) to make it an instance, or set lvl=-1*tgt_level. (note for the prt, the item=-1 means that the portal is permanent, otherwise it is a town portal)

heroic mino halls portal, illustrating value=-1*tgt_level ... item=-1 makes portal permanent
heroic.PNG
entrance to matriarch's domain, while not using spawner script, is an instance for some reason. note item=-1
instance.PNG
entrance to apoc minos, which converts spawners into blood, scorpions, etc. a separate script converts the map tiles
blood.PNG

Code: Select all

function spawnerHeroic(m)

  if m==nil then return int_rand(3)+2; end
  scaleCreature(m, 3, 4);
end

function spawnerEpic(m)

  if m==nil then return int_rand(3)+4; end
  scaleCreature(m, 5, 6);
end

function scaleCreature(m, c, qBump)

  m.hp=m.hp*c
  m:set_hp_max(m.hp)
  m.xp_kill=m.xp_kill*c
  local ot=m:get_thaco()
  local nt=(ot-10)*c+10 -- bad for low orig thaco
  local nt2=(ot+c*5) -- new formula for low startin thaco
  if nt2>nt then nt=nt2; end -- use higher of 2
  m:set_thaco(nt)
  m:set_base_ac(m:get_ac()+10*(c-1))
  m:set_intel(m:get_intel()*c)
  local mr=m:get_magic_resistance()*c
  if mr>9999 then mr=9999; end
  m:set_magic_resistance(mr)
  m:set_dmg_dice(m:get_dmg_dice()*c/2)

  q=m.treasure/0x10000
  q=q+qBump
  if q>0x13 then q=0x13 end
  m.treasure=(m.treasure & 0xffff)+q*0x10000

  m.tamable=false

end
You do not have the required permissions to view the files attached to this post.
Post Reply