Modcraft - The community dedicated to quality WoW modding!
Wrath of the Lich King Modding => Miscellaneous => Topic started by: jar0fair on July 29, 2015, 10:24:52 pm
-
Greetings,
I am hoping that I might find some advice on getting a system working which would allow our players to use items in their bags to spawn temporary objects. I currently have a lua script which can add the objects well enough. But, what I can’t figure out how to do, is to give the player the ability to remove the object by using the item again. At the moment, it just spawns another object. While I’m at it, I would also like to ensure that the item will only allow one instance of the object to be spawned at any given time. The main issue I see is that once the item is spawned, it is temporary, so it does not have a GUID, and thus, I can’t target it for removal.
If anyone has any ideas on how to make this work, I would really appreciate the input.
Thanks.
-
What core / lua engine are you using?
On trinitycore all objects have a guid - however Im unsure if you can use it to get the object.
In any case when spawing an object the spawn function usually returns a reference to the object.
This reference could be used to identify and maybe access the object later on.
However such access is dangerous without guaranteeing the object still exists (dangling pointer).
A grid search with checking the guid might be a better way if needing access after time has passed.
Can you post what you have already?
-
To answer your first question I am running An Eluna Trinity core, and I know your name, Rochet, I'm using some of your systems. Thank for those, btw. The code I am using basically spawns a temporary object when it's corresponding Item is used, where the player stands. When the player logs off, the object disappears. It's pretty simple at the moment and lacks the capabilities I mentioned in my op.
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local function SpawnObj(plr, entry, despawn_time)
plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
end
local function Cauldron(event, plr, item, target)
SpawnObj(plr, CauldronObj, 0)
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(vendortentItem, 2, VendorTent)
The idea here is that this script could grow as I add more objects to the list.
In a perfect world, what I want it to do, is what the temporary spawning in "Go Move" does, only to remove the object, you would simply use the item once more.
-
GOMove is just stabbing the existing systems.
The temporary object guids are hacked into the system so that the high part is used as the spawn ID even if that is not intended. The objects are saved to some gameobject storage system used by spells.
Would probably code it a bit differently on the spell storage part now..
Yeah, tested and you should be able to use the guid:
local x,y,z,o = plr:GetLocation()
local tar = plr:SpawnCreature( 36, x, y, z, o )
-- save guid somewhere, I save it to global variable GUIDL, but then again this is just an example code
GUIDL = tar:GetGUID()
-- Later access the creature by the saved guid:
local creature = plr:GetMap():GetWorldObject( GUIDL )
creature:SendUnitSay("asd", 0)
ps. even though I wrote this for creaturem same code works with gameobjects except gameobjects cant say stuff :P
-
Thanks, so I tried to integrate your code in a way that made sense to me. But, It isn't working. I'm sorry if I'm retarded. Please don't hit me.
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local GUIDL = 0
local function SpawnObj(plr, entry, despawn_time)
tar = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
GUIDL = tar:GetGUID()
end
local function Cauldron(event, plr, item, target)
if GUIDL:IsInWorld() == "IsInWorld" then
GUIDL:RemoveFromWorld( deleteFromDB )
else SpawnObj(plr, CauldronObj, 0 )
end
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(VendortentItem, 2, VendorTent)
-
Didn't test it, but i think you can get the logic out of it. :)
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local GUIDL
local function SpawnObj(plr, entry, despawn_time)
if GUIDL then
local spawnedGobject = plr:GetMap():GetWorldObject(GUIDL)
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
GUIDL = nil
end
else
local gobject = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
GUIDL = gobject:GetGUID()
end
end
local function Cauldron(event, plr, item, target)
SpawnObj(plr, CauldronObj, 0)
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(vendortentItem, 2, VendorTent)
-
Wow 10/10, thanks. This works, and the objects despawn on teh second use. But, are you ready for the next issue? If I spawn the chair, and then someone else has the chair item, and they try to spawn one, it de-spawns mine. I'm wondering if there is a way to have the code function differently for each player.
-
Wow 10/10, thanks. This works, and the objects despawn on teh second use. But, are you ready for the next issue? If I spawn the chair, and then someone else has the chair item, and they try to spawn one, it de-spawns mine. I'm wondering if there is a way to have the code function differently for each player.
Create a table and use it like this:
gameobjectlist[playerguid] = gobject:GetGUID()
If you can't do it with that hint, just tell us and we'll show you. :)
(This is better for learning purposes instead of spoon feeding you :P)
-
Like Kaev said you should look into using a lua table.
Getting this stuff to work is not so stright forward though. You need to think about special cases.
For example if you try to fetch an object that is on another map it will return nil
If you try to fetch an object that is in an unloaded grid of the map you are on it will return nil
So that said, you can make it so that spawning an object on a map will block you from spawning on other maps or on same map until you successfully delete the already spawned object.
Or you block spawning from same map but allow spawning on other maps.
Or you allow spawning as long as the already spawned object is not within set distance of the player or similar.
-
Wow 10/10, thanks. This works, and the objects despawn on teh second use. But, are you ready for the next issue? If I spawn the chair, and then someone else has the chair item, and they try to spawn one, it de-spawns mine. I'm wondering if there is a way to have the code function differently for each player.
Create a table and use it like this:
gameobjectlist[playerguid] = gobject:GetGUID()
If you can't do it with that hint, just tell us and we'll show you. :)
(This is better for learning purposes instead of spoon feeding you :P)
Thank you, I really am trying to learn how to do this stuff myself but, I am pretty new yet. Getting pretty frustrated with myself for not being able to figure it out. I've seen how to structure a table once or twice, but I don't think I am doing it right. This is what I did.
local spawns = {
GUIDL
owner = unit
}
local function SpawnObj(plr, entry, despawn_time)
if spawns[2] then
local spawnedGobject = plr:GetMap():GetWorldObject(GUIDL)
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawns = {
GUIDL = nil
owner = unit
}
end
else
local gobject = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
spawns = {
GUIDL = gobject:GetGUID()
owner = unit
}
end
end
-
Wow 10/10, thanks. This works, and the objects despawn on teh second use. But, are you ready for the next issue? If I spawn the chair, and then someone else has the chair item, and they try to spawn one, it de-spawns mine. I'm wondering if there is a way to have the code function differently for each player.
Create a table and use it like this:
gameobjectlist[playerguid] = gobject:GetGUID()
If you can't do it with that hint, just tell us and we'll show you. :)
(This is better for learning purposes instead of spoon feeding you :P)
Thank you, I really am trying to learn how to do this stuff myself but, I am pretty new yet. Getting pretty frustrated with myself for not being able to figure it out. I've seen how to structure a table once or twice, but I don't think I am doing it right. This is what I did.
local spawns = {
GUIDL
owner = unit
}
local function SpawnObj(plr, entry, despawn_time)
if spawns[2] then
local spawnedGobject = plr:GetMap():GetWorldObject(GUIDL)
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawns = {
GUIDL = nil
owner = unit
}
end
else
local gobject = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
spawns = {
GUIDL = gobject:GetGUID()
owner = unit
}
end
end
You're doing it wrong.
You can create a table like this:
local table = {}
and now you can access the table like
table[123] = "foo"
table["bar"] = 234
table[2] = 12345
and get the value like
local tablevalue = table[123] -- this will return "foo"
local tablevalue2 = table["bar"] -- this will return 234
local tablevalue3 = table[2] -- this will return 12345
You can find more about tables here: http://lua-users.org/wiki/TablesTutorial (http://lua-users.org/wiki/TablesTutorial" onclick="window.open(this.href);return false;)
A small example how you could use it
table[plr:GetGUID()] = gobject:GetGUID() -- now you can access the GUID of the object via the GUID of the player
-
local spawn = {}
local function SpawnObj(plr, entry, despawn_time)
if spawn then
local spawnedGobject = plr:GetMap():GetWorldObject(spawn[plr:GetGUID()])
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawn[plr:GetGUID()] = nil
end
else
local gobject = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
spawn[plr:GetGUID()] = gobject:GetGUID()
end
end
Thanks, that actually helped, and I've redone what I had before. I feel like I am getting really close but, I still can't get it to function. I've tried several different ways and invariably I am getting an error, when I use any of the items in game, in the following line:
local spawnedGobject = plr:GetMap():GetWorldObject(spawn[plr:GetGUID()])
"bad argument #1 to "GetWorldObject' (bad argument : unsigned long long expected, got nil)
-
This is because in your code you check
if spawn then
But spawn is always defined. The check is useless.
The code inside the IF statement is run and it errors because the value for the key plr:GetGUID() is nil in the spawn table.
What you should check instead is
if spawn[plr:GetGUID()] then
-
This is because in your code you check
if spawn then
But spawn is always defined. The check is useless.
The code inside the IF statement is run and it errors because the value for the key plr:GetGUID() is nil in the spawn table.
What you should check instead is
if spawn[plr:GetGUID()] then
Thanks, I appreciate everyone's help But...This just isn't working. The code now spawns the object, but it's back to the original state. It spawns unlimited amounts and does not despawn, even though the code tells it to. I am not sure what I am missing.
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local spawn = {}
local function SpawnObj(plr, entry, despawn_time)
if spawn[plr:GetGUID()] then
spawn[plr:GetGUID()]:RemoveFromWorld(true)
spawn[plr:GetGUID()] = nil
else
gobject = plr:SummonGameObject(entry, plr:GetX(), plr:GetY(), plr:GetZ(), plr:GetO(), despawn_time)
spawn[plr:GetGUID()] = gobject:GetGUID()
end
end
local function Cauldron(event, plr, item, target)
SpawnObj(plr, CauldronObj, 0)
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(VendortentItem, 2, VendorTent)
-
Try this. I basically just added back in the GetWorldObject you removed.
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local spawn = {}
local function SpawnObj(plr, entry, despawn_time)
local guid = plr:GetGUID()
if spawn[guid] then
local spawnedGobject = plr:GetMap():GetWorldObject(spawn[guid])
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawn[guid] = nil
else
plr:SendNotification("You need to be closer to the existing object to despawn it")
end
else
local x, y, z, o = plr:GetLocation()
local gobject = plr:SummonGameObject(entry, x, y, z, o, despawn_time)
if gobject then
spawn[guid] = gobject:GetGUID()
end
end
end
local function Cauldron(event, plr, item, target)
SpawnObj(plr, CauldronObj, 0)
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(VendortentItem, 2, VendorTent)
-
Try this. I basically just added back in the GetWorldObject you removed.
-- Cauldron
local CauldronItem = 200001
local CauldronObj = 186472
-- Chair
local ChairItem = 200002
local ChairObj = 186732
-- bed
local BedItem = 200003
local BedObj = 13948
-- vendor tent
local VendortentItem = 200004
local VendortentObj = 4000668
local spawn = {}
local function SpawnObj(plr, entry, despawn_time)
local guid = plr:GetGUID()
if spawn[guid] then
local spawnedGobject = plr:GetMap():GetWorldObject(spawn[guid])
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawn[guid] = nil
else
plr:SendNotification("You need to be closer to the existing object to despawn it")
end
else
local x, y, z, o = plr:GetLocation()
local gobject = plr:SummonGameObject(entry, x, y, z, o, despawn_time)
if gobject then
spawn[guid] = gobject:GetGUID()
end
end
end
local function Cauldron(event, plr, item, target)
SpawnObj(plr, CauldronObj, 0)
end
local function Chair(event, plr, item, target)
SpawnObj(plr, ChairObj, 0)
end
local function Bed(event, plr, item, target)
SpawnObj(plr, BedObj, 5)
end
local function VendorTent(event, plr, item, target)
SpawnObj(plr, VendortentObj, 0)
end
RegisterItemEvent(CauldronItem, 2, Cauldron)
RegisterItemEvent(ChairItem, 2, Chair)
RegisterItemEvent(BedItem, 2, Bed)
RegisterItemEvent(VendortentItem, 2, VendorTent)
Nope, It doesn't remove the objects, and I am not sure why, because, it really seems like would, reading the code.
-
Nope, It doesn't remove the objects, and I am not sure why, because, it really seems like would, reading the code.
Are you getting any errors?
The script does nothing after spawning one gameobject? No more spawns or any messages?
-
Alright, I see the error now.
Change
local guid = plr:GetGUID()
to
local guid = plr:GetGUIDLow()
The difference here is that GetGUID returns an uint64 number which is represented as an object.
Each GetGUID returns a different object causing the lua table to map them to different locations.
GetGUIDLow returns a normal number.
To properly make the uint64 work as table key it might need to be converted to strings, but using lowguid is easier for this and might be faster.
-
Alright, I see the error now.
Change
local guid = plr:GetGUID()
to
local guid = plr:GetGUIDLow()
The difference here is that GetGUID returns an uint64 number which is represented as an object.
Each GetGUID returns a different object causing the lua table to map them to different locations.
GetGUIDLow returns a normal number.
To properly make the uint64 work as table key it might need to be converted to strings, but using lowguid is easier for this and might be faster.
Thank you so much! Both of you. It is finally working how I would like it to. Me and my entire team are very grateful.
-
Hia, back again.
After a lot of testing I discovered that if I log out, with one of my objects spawned, and it disappears, I can no long use the item anymore without reloading the lua engine. This is because the object is gone, and the code does not recognize it. So, I have written an additional function to nil the spawns on logout. However, it does not work. I am wondering if anyone sees any glaring mistakes in the logout function that I am somehow missing.
-- Name Here
local item = 200002
local obj = 22713
-- Code
local spawn = {}
local function SpawnObj(plr, entry, despawn_time)
local guid = plr:GetGUIDLow()
if spawn[guid] then
local spawnedGobject = plr:GetMap():GetWorldObject(spawn[guid])
if spawnedGobject then
spawnedGobject:RemoveFromWorld(true)
spawn[guid] = nil
end
else
local x, y, z, o = plr:GetLocation()
local gobject = plr:SummonGameObject(entry, x, y, z, o, despawn_time)
if gobject then
spawn[guid] = gobject:GetGUID()
end
end
end
local function logoff(plr, entry)
guid = plr.GetGUIDLow()
spawn[guid] = nil
end
-- Spawn Function
local function use(event, plr, item, target)
SpawnObj(plr, obj, 0)
end
-- Registers
RegisterItemEvent(item, 2, use)
RegisterPlayerEvent(4, logoff)
-
local function logoff(plr, entry)
guid = plr.GetGUIDLow()
spawn[guid] = nil
end
Erm .. thats ..
The reason the code doesnt work is because your parameters are wrong logoff(plr, entry).
If you look here: http://eluna.emudevs.com/Global/Registe ... Event.html (http://eluna.emudevs.com/Global/RegisterPlayerEvent.html" onclick="window.open(this.href);return false;) it says (event, player)
also make that guid variable local.
Also you call member functions with : not with a dot.
-
Thanks again, Rotchet, this works just how I needed it to, now. Couldn't have done it without you.