Jump to content
Sign in to follow this  
GDLib

The OpenTibia NPC System

Recommended Posts

GDLib    2
GDLib

Olá a todos, para quem não sabe, sou Nostradamus e a algum tempo, tive minha atividade cessada no projeto OpenTibia como Scripting Leader Developer, mas, não estou afim de sair de uma comunidade que me fez descobrir uma das linguagens que mais uso hoje profissionalmente, Lua. Depois de ler um post do Forger sobre motivação, resolvi dar uma última oportunidade a todos, de experimentarem o verdadeiro OpenTibia.

 

Fiquei encarregado de criar um NPC System para substituir o do Jiddo no OpenTibia oficial, eu poderia muito bem fazer sozinho, ou dizer não a eles, mas resolvi que todos irão participar dessa façanha.

 

Por meio desse post, irei desenvolver junto com todos vocês, o sistema, partindo de sugestões, idéias, opiniões, patchs, críticas, algorítimos, enfim, quero a sua ajuda, não me interessa se você sabe ou não Lua, eu quero a sua opinião de como deveseria ser um NPC System bom, fácil, rápido e decente.

 

Eis aqui umas condições de como ajudar:

 

  • É terminantemente proibido a rippagem de códigos de outros sem a devida autorização dos autores.
  • As contribuições devem ser postadas com escrita correta.
  • Não é permitido offtopics nesse post.
  • As idéias que forem idênticas umas das outras, permanecerá os créditos do primeiro idealizador (o que postar primeiro).
  • Sua contribuição é algo formal ao projeto, portanto, seja o mais formal possível e esteja crente que estará ajudando toda a comunidade OpenTibia.

 

Desenvolvedores

 

  • Ambiente orientado a objetos
  • Uso incessante de tabelas para configuração
  • Debug strackback
  • Changelogs
  • Tratamento de erros dinâmizados
  • Condicionamento baseado em eventos
  • Modulação
  • Convenções baseadas no padrão OpenTibia (ver Guidelines

 

Script inicial

 

--[[
The OpenTibia NPC System 0.1
Features
	ratePrice multiplier
	Buy/Sell/Teleport/Spell modules
	Dynamic error threatment

Todo
	Debugger Strackback (configurable tables and advanced error reporting)
	Otmization of all the functions
	Rewrite doPlayerAddMoney (that one from Piterb sucks)
	onThink and onQueue events
	onTalk event with dynamic uses of talkstates and so on
		sub-talkstates will be sub-arrays of the main talkstate refered to it
		messages will be handled into arrays with the input and output of the NPC (message and answer subarrays)
	Function to list buying/selling items, teleport places and spells
	Study the possibility of the usage of a new "msgContains" function with tolerance (if a player write the "key" wrong, it will return the correct input)
	Promote and quest module
	Extra module to get the statitics (how much items were sold, bought, etc)
	Optmize Buy/Sell functions to accept containers with items
	Study the possibility to divide the class "NPC" into modules or events

Notes
	Since this script uses object orientation with a default class, there isn't reasons to make conditions considering if there is or not a value, since it will 
	always be called when executing this script. The array "NPC" is a global array that will handle with all NPC scripts and with all the functions of that class.

--]]

NPC = 
{
ratePrice = 1, 

-- This arrays are used only if not declared in the script, it will be always global values (access by the global table [_G])
BUY_LIST =
{
	["item_name"] = {id = , price = , count = }
},

SELL_LIST =
{
	["item_name"] = {id = , price = , count = }
},

TELEPORT_PLACES =
{
	["name"] = {pos = {x = , y = , z = }, price = }
},

SPELL_LIST =
{
	["name"] = {words = , price = , level =, maglevel = }
},

-- In the future, it will be used as a debugger strackback
ERRORS =
{
	maxCount = "Item count should be less then 100.",
	noCount = "Item count should be especified.",
	noMoney = "The player does not have enought money.",
	noItem = "Desired item not found in the buying list.",
	noPlayerItem = "The player does not have the item to sell it.",
	noPlace = "Desired place does not exists."
}

}

-- NPC Class Instance
function NPC:new()
o = o or {}
   return setmetatable(o, self)
self.__index = self
return o
end

-- TODO: optmize this function
function NPC.doPlayerAddMoney(cid, amount)
	local crystals = math.floor(amount / 10000)
		amount = amount - crystals * 10000
	local platinum = math.floor(amount / 100)
		amount = amount - platinum * 100

	local gold, ret = amount, 0

	if (crystals > 0) then
		ret = doPlayerAddItem(cid, ITEM_CRYSTAL_COIN, crystals)
		if (ret ~= LUA_NO_ERROR) then
			return LUA_ERROR
		end
	end

	if (platinum > 0) then
		ret = doPlayerAddItem(cid, ITEM_PLATINUM_COIN, platinum)
		if (ret ~= LUA_NO_ERROR) then
			return LUA_ERROR
		end
	end
	if (gold > 0) then
		ret = doPlayerAddItem(cid, ITEM_GOLD_COIN, gold)
		if (ret ~= LUA_NO_ERROR) then
			return LUA_ERROR
		end
	end
	return LUA_NO_ERROR
end			

function NPC:Buy(cid, itemName, count, array)
	-- Maybe should be moved into the main scope in the future
	if (array ~= nil) then
		item = self.BUY_LIST[itemName]
	else	
		item = array[itemName]
	end
	local totalCount, totalPrice = item.count + count, (item.price * count) * self.ratePrice 
	if (item ~= nil) then
		if (doPlayerRemoveMoney(cid, totalPrice) == TRUE) then
			if (item.count ~= nil) then
				if (totalCount <= 100) then
					-- TODO: Support to charges and counts separately
					doPlayerAddItem(cid, item.id, totalCount)
					doPlayerRemoveMoney(cid, totalPrice)
					return TRUE
				else
					return self.ERRORS.maxCount
				end
			else
				return self.ERRORS.noCount
			end
		else
			return self.ERRORS.noMoney
		end
	else
		return self.ERRORS.noItem
		--[[ for i = array[1], #array do
			return i.name .. i.price .. i.count
		end --]]
	end
end

function NPC:Sell(cid, itemName, count, array)
	-- Maybe should be moved into the main scope in the future
	if (array ~= nil) then
		item = self.SELL_LIST[itemName]
	else	
		item = array[itemName]
	end
	local totalCount, totalPrice = item.count + count, (item.price * count) * self.ratePrice 
	if (item ~= nil) then
		if (getPlayerItemCount(cid) >= count) then
			if (item.count ~= nil) then
				if (totalCount <= 100) then
					doPlayerRemoveItem(cid, item.id, totalCount)
					self.doPlayerAddMoney(cid, totalPrice)
					return TRUE
				else
					return self.ERRORS.maxCount
				end
			else
				return self.ERRORS.noCount
			end
		else
			return self.ERRORS.noPlayerItem
		end
	else
		return self.ERRORS.noItem
		--[[ for i = array[1], #array do
			return i.name .. i.price .. i.count
		end --]]
	end
end

function NPC:Teleport(cid, placeName, array)
	if (array ~= nil) then
		place = self.TELEPORT_PLACES[placeName]
	else	
		place = array[placeName]
	end
	if (place ~= nil) then
		if (doPlayerRemoveMoney(cid, place.price + self.ratePrice) == TRUE) then
			doTeleportThing(cid, place.pos)
		else
			return self.ERRORS.noMoney
		end
	else
		return self.ERRORS.noPlace
	end
end

function NPC:doPlayerLearnSpell(cid, spellName, array)
	if (array ~= nil) then
		spell = self.SPELL_LIST[spellName]
	else	
		spell = array[spellName]
	end
	if (spell ~= nil) then
		if (getPlayerLearnedInstantSpell(cid, spellName) == TRUE) then
			return self.ERRORS.alreadyLearned
		elseif (spell.level > getPlayerLevel(cid)) then
			return self.ERRORS.noLevel
		elseif (spell.maglevel > getPlayerMagLevel(cid)) then
			return self.ERRORS.noMagLevel
		elseif (canPlayerLearnInstantSpell(cid, spellName) == FALSE) then
			return self.ERRORS.noVocation
		elseif (doPlayerRemoveMoney(cid, spell.price == TRUE) then
			playerLearnInstantSpell(cid, spellName)
		else
			return self.ERRORS.unknown
	else
		return self.ERRORS.noSpell
	end
end	

-- Incomplete
function NPC:onSay(msg, delay)
	if (msg ~= nil) then
		if (delay > 0) then
			-- Incomplete
		else
			selfSay(msg)
		end
	end
end

-- Incomplete
local messages = {
	[talkstate] = {message = "Hi", answer = "Hello"}
}

function NPC:onTalk(msgArray)
	-- Incomplete
end

 

Modelo de sugestão

 

Deveria-se haver um modo de se configurar o NPC de forma mais dinâmica e claro de modo que o script não tenha muitas linhas. (Nostradamus)

 

Modelo de idéia

 

Talktimes e eventos deveriam ser revistos, talvez haja uma maneira mais dinâmica de se fazer sub-conversas. (Nostradamus)

 

Modelo de post

 

Sugestão (e/ou) idéia (e/ou) patch (e/ou) crítica

 

 

Pedido

 

Gostaria de pedir à administração do OTNet para que encarregue um moderador para que o mesmo delete posts considerados inúteis ou que fogem das regras. O custeador (OTNet) será creditado na Official OpenTibia Project.

 

Boa sorte a todos!

Share this post


Link to post
Share on other sites
Forger    2
Forger

Gostei bastante da idéia.

Na verdade, estava começando a desenvolver um NPC System também. ^^

Acredito que posso te ajudar nessa tarefa como developer. :)

 

Vou te enviar por PM algumas idéias que tinha, como seria, etc. ;)

Esperemos que esse projeto dê certo. :D

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×