Ich habe mich heute mal an eine Basic Pet-Quest gesetzt. Die Boni können in der Datenbank eingestellt werden.
Ob das ganze funktioniert weiss ich nicht, weil ich zurzeit keinen Server zum Testen zur Verfügung habe. Bei Fehlern immer gerne hier im Thread melden!
Vorraussetzungen:
game.mysql_query Funktion, welche die Datensätze im Format [dataset][columnIndex] zurückgibt
Installation:
Den SQL Teil aus dem obersten Kommentarblock in die Datenbank "player" einfügen
Den Questlib Teil in die Questlib einfügen
Wenn ipairs noch nicht in der quest_functions steht, einfügen
Vnums im Trigger (vnum.use) durch die der Siegel ersetzen (Siegel muss Type 18 sein!)
Quest einfügen und in die quest_list / locale_list eintragen
Pets in die vorher erstellte Tabelle (pet_info) eintragen (Achtung: Es werden Fremdschlüssel benutzt. Heisst: Es können nur Siegel hinzugefügt werden, welche in der item_proto vorhanden sind und nur Monster eingetragen werden, welche in der mob_proto existieren!)
Boni der Pets in die vorher erstellte Tablle (pet_affect) eintragen (Achtung: Auch hier werden Fremdschlüssel benutzt. Es können die Bonis nur eingestellt werden, wenn dieses Siegel in der pet_info Tabelle existiert!)
Zu beachten:
Die Tabelle "pet_open_affects" wird dafür genutzt, die wirklich vergegeben Boni zu speichern. Wenn also der Boni des Pets in der Tabelle "pet_affect" geändert wird, und ein Spieler während dieser Zeit sein Pet gerufen hat, werden ihm die Boni weggenommen, die er auch bekommen hat, und nicht die, die neu eingestellt wurden. Das leeren der pet_open_affects Tabelle löscht NICHT die Boni der Spieler!
Die Quest:
Code:
--[[
SQL:
CREATE TABLE pet_info (
itemVnum int(11) NOT NULL,
mobVnum int(11) NOT NULL,
PRIMARY KEY(itemVnum),
FOREIGN KEY(itemVnum) REFERENCES item_proto(vnum),
FOREIGN KEY(mobVnum) REFERENCES mob_proto(vnum)
);
CREATE TABLE pet_affect (
itemVnum int(11) NOT NULL,
affectID int(11) NOT NULL,
affectValue int(11) NOT NULL,
PRIMARY KEY(itemVnum, affectID),
FOREIGN KEY(itemVnum) REFERENCES pet_info(itemVnum)
);
CREATE TABLE pet_names (
pid int(11) NOT NULL,
itemVnum int(11) NOT NULL,
name varchar(12) NOT NULL,
PRIMARY KEY(pid, itemVnum),
FOREIGN KEY(itemVnum) REFERENCES pet_info(itemVnum)
);
CREATE TABLE pet_summoned (
pid int(11) NOT NULL,
itemVnum int(11) NOT NULL,
mobVnum int(11) NOT NULL,
PRIMARY KEY(pid, itemVnum)
);
CREATE TABLE pet_open_affects (
pid int(11) NOT NULL,
itemVnum int(11) NOT NULL,
affectID int(11) NOT NULL,
affectValue int(11) NOT NULL,
PRIMARY KEY(pid, itemVnum, affectID)
);
Questlib:
petMessage = {
SUMMON = {
SUCCESS = "Dein Haustier wurde zurückgeschickt.",
ERROR_NO_INFO = "SUMMON.ERROR_NO_INFO (Keine Info zum Siegel) - Bitte einem Teamler melden"
},
UNSUMMON = {
SUCCESS = "Dein Haustier wurde gerufen.",
ERROR_NO_INFO = "UNSUMMON.ERROR_NO_INFO (Keine Info zum Siegel) - Bitte einem Teamler melden"
}
}
]]
quest petSystem begin
state start begin
--Jedes Siegel 1x spawnbar
when 123.use begin
syschat(petSystem.summon(item.get_vnum()))
end
when login begin
--Looptimer to check if all summoned pets are still in the players inventory
loop_timer("check_pets", 5)
for _,itemVnum in ipairs(petSystem.getSummoned()) do
--Message is not going to be printed when logging in
petSystem.summon(itemVnum, true)
end
end
when check_pets.timer begin
for _,itemVnum in ipairs(petSystem.getSummoned()) do
if pc.count_item(itemVnum) < 1 then
syschat("Das Siegel eines von dir gerufenen Haustieres wurde nicht mehr in deinem Inventar gefunden.")
syschat(petSystem.unsummon(itemVnum))
end
end
end
--[[
summon(itemVnum)
Summons the pet by the given itemVnum
Parameters:
itemVnum The item used to summon the pet
force If summon should be forced (default = false)
Returns: petMessage.SUMMON or (if unsummon was called) petMessage.UNSUMMON
]]
function summon(itemVnum, force)
local force = force or false
if petSystem.isSummoned(itemVnum) then
local msg = petSystem.unsummon(itemVnum)
if not force then
return msg
end
end
local currentInfo = petSystem.getCurrentInfo(itemVnum)
if not currentInfo then return petMessage.SUMMON.ERROR_NO_INFO end
local pid = pc.get_player_id()
for _,affectPair in ipairs(currentInfo.affectData) do
affect.add_collect(affectPair[1], affectPair[2], 60*60*24*365*10)
game.mysql_query("INSERT INTO player.pet_open_affects (pid, itemVnum, affectID, affectValue) VALUES ("..pid..", "..itemVnum..", "..affectPair[1]..", "..affectPair[2]..");")
end
local petName = petSystem.getPetName(itemVnum) or mob_name(currentInfo.mobVnum)
pet.summon(currentInfo.mobVnum, (" - "..petName), false)
game.mysql_query("INSERT INTO player.pet_summoned (pid, itemVnum, mobVnum) VALUES ("..pid..", "..itemVnum..", "..currentInfo.mobVnum..");")
return petMessage.SUMMON.SUCCESS
end
--[[
unsummon(itemVnum)
Unsummons the pet by the given itemVnum
Parameters:
itemVnum The item used to summon the pet
Returns: petMessage.UNSUMMON
]]
function unsummon(itemVnum)
local summonedInfo = petSystem.getSummonedInfo(itemVnum)
if not summonedInfo then return petMessage.UNSUMMON.ERROR_NO_INFO end
local pid = pc.get_player_id()
for _,affectPair in ipairs(summonedInfo.affectData) do
affect.remove_collect(affectPair[1], affectPair[2])
game.mysql_query("DELETE FROM player.pet_open_affects WHERE pid = "..pid.." AND itemVnum = "..itemVnum.." AND affectID = "..affectPair[1].." LIMIT 1;")
end
pet.unsummon(summonedInfo.mobVnum)
game.mysql_query("DELETE FROM player.pet_summoned WHERE pid = "..pid.." AND itemVnum = "..itemVnum.." LIMIT 1;")
return petMessage.UNSUMMON.SUCCESS
end
--[[
isSummoned(itemVnum)
Checks if the pet with the given itemVnum is summoned
Parameters:
itemVnum The item used to summon the pet
Returns: boolean (true, if pet is already summoned)
]]
function isSummoned(itemVnum)
return in_list(itemVnum, petSystem.getSummoned())
end
--[[
getSummoned()
Returns all itemVnums of which a pet is summoned
Paramters:
//
Returns: table of all itemVnums currently summoned by the player
]]
function getSummoned()
local pid = pc.get_player_id()
local result = game.mysql_query("SELECT itemVnum FROM player.pet_summoned WHERE pid = "..pid..";") or false
if not result or table.getn(result) < 1 then return {} end
local summonedPets = {}
for _,v in ipairs(result) do
table.insert(summonedPets, tonumber(v[1]))
end
return summonedPets
end
--[[
getCurrentInfo(itemVnum)
Returns the current info for the given itemVnum from the database
Parameters:
itemVnum The item to search info for
Returns: false (if no info found to the itemVnum) or a table with the mobVnum and all affects (affect table can be empty)
]]
function getCurrentInfo(itemVnum)
local mobVnum = game.mysql_query("SELECT mobVnum FROM player.pet_info WHERE itemVnum = "..itemVnum.." LIMIT 1;") or false
if not mobVnum or table.getn(mobVnum) < 1 then return false end
local info = {mobVnum = tonumber(mobVnum[1][1]), affectData = {}}
local affectData = game.mysql_query("SELECT affectID, affectValue FROM player.pet_affect WHERE itemVnum = "..itemVnum..";") or false
if not affectData or table.getn(affectData) < 1 then return info end
for _,v in ipairs(affectData) do
table.insert(info.affectData, {tonumber(v[1]), tonumber(v[2])})
end
return info
end
--[[
getSummonedInfo(itemVnum)
Returns the summoned info for the given itemVnum of the player (e.g. affects have been changed but player summoned the pet before, this will return the affects the player got)
Parameters:
itemVnum The item to search info for
Returns: false (if no info found to the itemVnum in combination with the player) or a table with the mobVnum and all affects the player got by this pet
]]
function getSummonedInfo(itemVnum)
local pid = pc.get_player_id()
local mobVnum = game.mysql_query("SELECT mobVnum FROM player.pet_summoned WHERE pid = "..pid.." AND itemVnum = "..itemVnum.." LIMIT 1;") or false
if not mobVnum or table.getn(mobVnum) < 1 then return false end
local info = {mobVnum = tonumber(mobVnum[1][1]), affectData = {}}
local affectData = game.mysql_query("SELECT affectID, affectValue FROM player.pet_open_affects WHERE pid = "..pid.." AND itemVnum = "..itemVnum..";") or false
if not affectData or table.getn(affectData) < 1 then return info end
for _,v in ipairs(affectData) do
table.insert(info.affectData, {tonumber(v[1]), tonumber(v[2])})
end
return info
end
--[[
getPetName(itemVnum)
Returns the name the player gave his pet with the given itemVnum
Parameters:
itemVnum The item to search the name for
Returns: false (if no name set yet) or the petname
]]
function getPetName(itemVnum)
local pid = pc.get_player_id()
local petName = game.mysql_query("SELECT petName FROM player.pet_names WHERE pid = "..pid.." AND itemVnum "..itemVnum.." LIMIT 1;") or false
if not petName or table.getn(petName) < 1 then return false end
return petName[1][1]
end
--[[
setPetName(itemVnum, name)
Sets the petname for the given itemVnum
Parameters:
itemVnum The item to set the name for
name The name to set
Returns:
//
]]
function setPetName(itemVnum, name)
local pid = pc.get_player_id()
game.mysql_query("INSERT INTO player.pet_names (pid, itemVnum, name) VALUES ("..pid..", "..itemVnum..", '"..name.."') ON DUPLICATE KEY UPDATE name = '"..name.."';")
end
end
end
when check_pets.timer begin
for _,itemVnum in ipairs(petSystem.getSummoned()) do
if pc.count_item(itemVnum) < 1 then
syschat("Das Siegel eines von dir gerufenen Haustieres wurde nicht mehr in deinem Inventar gefunden.")
syschat(petSystem.unsummon(itemVnum))
end
end
end
Den Teil brauchst du eigentlich garnicht mehr seit 34k Game(glaube ich) beim Source aufjedenfall nicht, denn sobald du das Siegel weggibst verschwindet dein Pet