• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[New system for npc] All npc-scripts in one file?

Joined
Apr 17, 2008
Messages
1,922
Solutions
1
Reaction score
188
Location
Venezuela
Hello, i've been working on a new system, that let's you create all npc-scripts in just one file.
With this you don't need to create a file for each npc in folder data/npc/scripts...

All npcs will use the same file, but the actions will change of course (transcripts, trade, travel, etc)

Basically, you only need to specify the npc name, outfit and others parameters in the file and then when the server starts, it'll create the npc (Creating the .xml file in folder data/npc) and after creating it, reloading the NPCS and then the new npcs will be added to your server.

This is an example (Using Yasir)
Lua:
Yasir = Npc:new("Yasir")
			Yasir.type = 146
			Yasir.head = 85
			Yasir.body = 7
			Yasir.legs = 12
			Yasir.feet = 19
			Yasir.addons = 2
			Yasir.walkinterval = 4000
			Yasir.speed = 100
			Yasir.floorchange = 0
			Yasir.access = 3
			Yasir.healthnow = 300
			Yasir.healthmax = 300

			Yasir.MESSAGE_GREET = "Yasu me halaka. <greets you friendly>"
			Yasir.MESSAGE_FAREWELL = "Si, jema ze harun. <waves>"
			Yasir:setTradeList(YasirTrade)
			Yasir:onSell(function (cid, item, subType, amount)
							local shop = {}
							for _, it in ipairs(Yasir.tradelist) do
								shop[it.id] = {sell = it.sell, name = (it.name or getItemNameById(it.id))}
							end
							if getPlayerItemCount(cid, item) >= amount and doPlayerRemoveItem(cid, item, amount) then
								doPlayerAddMoney(cid, amount * shop[item].sell)
								doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Sold x" .. amount .. " " .. shop[item].name .. " for " .. shop[item].sell * amount .. " gold.")
							else
								return doPlayerSendCancel(cid, "You do not have that item.")
							end
						end)
						
			Yasir.onThink = function(npc)
								return doCreatureSay(npc, "Thinking!", TALKTYPE_SAY) --Example
							end
			Yasir.onThinkInterval = 30

			int = Behaviour:new()
			int.words = {"trade", "ariki"}
			int.response = "Si! Haneka ariki!"
			int.action = function (cid, type, msg)
								if doPlayerAddAchievement then
									doPlayerAddAchievement(cid, "Si, Ariki!", true)
								end
								openShopWindow(cid, Yasir.tradelist, Yasir.onBuy, Yasir.onSell)
							end
			Yasir:addBehaviour(int)

			int = Behaviour:new()
			int.words = {"name"}
			int.response = "Me Yasir." --or you can use "Me $npcname."
			int.npcChannel = true
			Yasir:addBehaviour(int)

			int = Behaviour:new()
			int.words = {"job"}
			int.response = "Tje hari ku ne finjala. {Ariki}?"
			Yasir:addBehaviour(int)

			int = Behaviour:new()
			int.words = {"passage"}
			int.response = "Soso yana. <shakes his head>"
			Yasir:addBehaviour(int)
			
			int = Behaviour:new()
			int.words = {"my name"}
			int.response = "Your name is $playername and my name is $this.name" --Testing some format-variables (Can use |NPCNAME|, $npcname and $this.name)
			Yasir:addBehaviour(int)

			Yasir:print() ---Creates npc and reloads the server

What do you think about something like this?
 
Last edited:
I see this feathures in revscriptsys2 (OpenTibia Project from Sourceforge.com). There's example NPC:
Lua:
local Michael = NPC:new("Michael")

Michael.outfit = {
	type = 130,
	head = 20,
	body = 15,
	legs = 10,
	feet = 5
}

Michael.greeting = {"Hello $name.", "Greetings $name."}
Michael.farewell = {"Goodbye $sir $name."}
Michael.runoff = {"How rude!"}

Michael.idleTimeout = 30
Michael.listenRadius = 4
Michael.walkRadius = 3

--[[
Michael.dialog =
	{
		{ { "heal$", isBurning() }, { "You are burning, I will help you.", healBurning(), playerEffect(EFFECT_SOMETHING) } };
		{ { "heal$", isPoisoned() }, { "You are poisoned, I will help you.", healPoison(), playerEffect(EFFECT_SOMETHING) } };
		{ { "heal$", hasHealth(40) }, { "You are badly wounded, let me help you.", setHealth(40), playerEffect(EFFECT_SOMETHING) } };
		{ { "heal$", isPvpEnforced() }, "You aren't looking that bad." };
		{   "heal$", "You aren't looking that bad. Sorry, I can't help you. But if you are looking for additional protection you should go on the pilgrimage of ashes."};

		{ { "blessing", isPvpEnforced() }, "The lifeforce of this world is waning. There are no more blessings avaliable on this world."};
		{   "pilgrimage", last};
		
		{   "sacred+places", "Just ask in which of the five blessings you are interested in."};
		
		{ { "spiritual", hasStorage("quest_carpet") }, "I see you received the spiritual shielding in the whiteflower temple south of Thais."};
		{   "spiritual", "You can receive the spiritual shielding in the whiteflower temple south of Thais."};

		{   "arena", ask("Do you want to go to the arena?", 
			{
				{ isPzBlocked(), "First finish your current fight!" };
				{ {}, "Then off with you!", travel {2030, 2003, 7} };
			},
			{ "Then stay here in serenity." }
		) };

		{"job|occupation", "My job is to be awesome."};
		{"queue", function(self) return "There is " .. #self.queue .. " people in queue." end};
		{"count my gold", function(self) return "You have " .. self.focus:countMoney() .. " gold." end};
		{"monologue", {"This message is split into several parts and should be presented after one other.", "Here comes the next part.", "And the next."}};
		
		--{"ab'dendriel", travel{122, 322, 7}};
		{ "highest", ask("Do you wanna play highest number?",
			function(self)
				self:say("Awesome, let's do it. You go first.")
				local n = nil
				while not n do
					n = tonumber(self:listen())
					if not n then
						self:say("That's not a number!")
					end
				end
				self:say((n + 1) .. "!")
				wait(1000)
				self:say("Seems I won, suck it.")
			end,
			"Too bad, it's a fun game."
		) };
		
		{"dialog", function(self)
			self:say("Do you want to continue this conversation?")
			local reply = self:listen()
			if containsAgreement(reply) then
				local n = 1
				local function loop(self)
					self:say("This is the " .. n .. " repeat of this phrase, want more?")
					n = n + 1
					local reply = self:listen()
					if containsAgreement(reply) then
						return loop(self)
					else
						self:say("Ok. Then let's talk about something else!")
					end
				end
				loop(self)
			else
				self:say("You didn't continue, resume normal conversation flow.")
			end
		end};
	}
]]--

Michael.trade = {
	{"mace", id=2398, buy=90, sell=30};
	{"empty vial|vial", type=0, id=2006, sell=5, sell_phrase="Do you want to exchange all your $itemcount vials for $price gold?", all = true};
	{name="mana fluid", type=7, id=2006, buy=100};
	{name="cellar key", actionID=1234, id=2087, buy=800};
}

function Michael:onHear(message, class)
	self:say("I don't understand that.")
end

You can download whole source there: SourceForge.net Repository - [opentibia] Index of /otserv/branches/revscriptsys2
 
I changed the whole system, now it works like this one
Lua:
YasirTrade = --table containing trade info ({id = ?, sell = ?, buy = ?[,name = ""]}
{ 
	{id = 11213, sell = 10},
	{id = 11214, sell = 50},
	{id = 5883, sell = 120},
}

Y = Npc:new("Yasir")
Y.type = 146
Y.head = 85
Y.body = 7
Y.legs = 12
Y.feet = 19
Y.addons = 2
Y.walkinterval = 4000
Y.floorchange = 0
Y.access = 2
Y.healthnow = 300
Y.healthmax = 300

Y.MESSAGE_GREET = "Yasu me halaka. <greets you friendly>"
Y.MESSAGE_FAREWELL = "Si, jema ze harun. <waves>"

Y.tradelist = YasirTrade
Y.onSell = function onSell(cid, item, subType, amount)
				local shop = {}
				for _, it in ipairs(self.tradelist) do
					shop[it.id] = {sell = it.sell, name = (it.name or getItemNameById(it.id))}
				end
				if getPlayerItemCount(cid, item) >= amount and doPlayerRemoveItem(cid, item, amount) then
					doPlayerAddMoney(cid, amount * shop[item].sell)
					doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Sold x" .. amount .. " " .. shop[item].name .. " for " .. shop[item].sell * amount .. " gold.")
				else
					return doPlayerSendCancel(cid, "You do not have that item.")
				end
			end

int = Behaviour:new()
int.words = {"trade", "ariki"}
int.response = "Si! Haneka ariki!"
int.action = function(cid, type, msg) 
					if doPlayerAddAchievement then
						doPlayerAddAchievement(cid, "Si, Ariki!", true)
					end
					openShopWindow(cid, Y.tradelist, Y.onBuy, Y.onSell)
				end
Y:addBehaviour(int)

int = Behaviour:new()
int.words = {"name"}
int.response = "Me Yasir." --or you can use "Me $npcname."
Y:addBehaviour(int)

int = Behaviour:new()
int.words = {"job"}
int.reponse = "Tje hari ku ne finjala. {Ariki}?"
Y:addBehaviour(int)

int = Behaviour:new()
int.words = {"passage"}
int.response = "Soso yana. <shakes his head>"
Y:addBehaviour(int)

Y:print() ---Creates npc and reloads the server
 
I like what you've done with the system. :)
 
I have mixed feelings about it. How would you make more complexed dialogs with npcs? Also implementation has to be quite easy so you wont get freaked after making a big dialog tree. In my opinion its nice try, but you should make it more about npc dialogs. Im kinda in progress of making similar thing but it will handle also few things at once: questlog, large dialog trees, quest storages (you will have to use just one storage for one mission) The hardesr part is to simplyfi code to point where its easy to use for ppl. I dont think I achived that. However, I like your try, code not that much ( my opinion my be not trustworth since I making soemthign similar xD) but have fun with that :D
 
the project is dead? i really wanna use some new npc system that is more like Cipsoft way of scripting
 
Back
Top