Page 1 of 1

Crash Adding New LUA Function

Posted: Wed Dec 10, 2008 10:47 am
by Scatman
LE, I added the following LUA spell:

Code: Select all

Index: LuaFunctions.cpp
===================================================================
--- LuaFunctions.cpp	(revision 175)
+++ LuaFunctions.cpp	(working copy)
@@ -102,6 +102,16 @@
 	return 0;
 }
 
+int EQ2Emu_lua_KillSpawn(lua_State* state) {
+	Spawn* dead = lua_interface->GetSpawn(state);
+	Spawn* killer = lua_interface->GetSpawn(state, 2);
+
+	if (dead && dead->GetZone())
+		dead->GetZone()->KillSpawn(dead, killer);
+
+	return 0;
+}
+
 int EQ2Emu_lua_KillSpawnByDistance(lua_State* state){
 	Spawn* spawn = lua_interface->GetSpawn(state);
 	float max_distance = lua_interface->GetFloatValue(state, 2);
Index: LuaFunctions.h
===================================================================
--- LuaFunctions.h	(revision 175)
+++ LuaFunctions.h	(working copy)
@@ -65,6 +65,7 @@
 int EQ2Emu_lua_GetLootCoin(lua_State* state);
 int EQ2Emu_lua_GetSpawn(lua_State* state);
 int EQ2Emu_lua_SpawnSet(lua_State* state);
+int EQ2Emu_lua_KillSpawn(lua_State* state);
 int EQ2Emu_lua_KillSpawnByDistance(lua_State* state);
 int EQ2Emu_lua_SpawnSetByDistance(lua_State* state);
 int EQ2Emu_lua_SetRequiredQuest(lua_State* state);
Index: LuaInterface.cpp
===================================================================
--- LuaInterface.cpp	(revision 175)
+++ LuaInterface.cpp	(working copy)
@@ -447,6 +447,7 @@
 	lua_register(state, "StartConversation", EQ2Emu_lua_StartConversation);
 	lua_register(state, "SpawnSet", EQ2Emu_lua_SpawnSet);
 	lua_register(state, "SpawnSetByDistance", EQ2Emu_lua_SpawnSetByDistance);
+	lua_register(state, "KillSpawn", EQ2Emu_lua_KillSpawn);
 	lua_register(state, "KillSpawnByDistance", EQ2Emu_lua_KillSpawnByDistance);
 
 	lua_register(state, "SetRequiredQuest", EQ2Emu_lua_SetRequiredQuest);
Sorry, Fileshare wouldn't let me upload a file then let you view it, you had to download it to view it. We tested a script out last night that used KillSpawn() and it all worked except we get a crash at the end. John sent this:

Code: Select all

>   EQ2WorldDebug.exe!operator delete(void * pUserData=0xdddddddd)  Line 52 + 0x3 bytes   C++
    EQ2WorldDebug.exe!Timer::`scalar deleting destructor'()  + 0x25 bytes   C++
    EQ2WorldDebug.exe!ZoneServer::CheckSpawnScriptTimers()  Line 1755 + 0x35 bytes   C++
    EQ2WorldDebug.exe!ZoneServer::Process()  Line 653   C++
    EQ2WorldDebug.exe!ZoneLoop(void * tmp=0x06f48540)  Line 2504 + 0x8 bytes   C++
    EQ2WorldDebug.exe!_callthreadstart()  Line 293 + 0xf bytes   C
    EQ2WorldDebug.exe!_threadstart(void * ptd=0x06f49110)  Line 277   C
    kernel32.dll!77e64829()    
    [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]    
I tried to look up what was going on but couldn't, for the life of me, figure out what was wrong. I tried searching the error and people on forums said this error is usually some kind of warning but it's clearly a crash. :P

Posted: Wed Dec 10, 2008 3:39 pm
by LethalEncounter
Could you also paste your script that was causing it to crash? It looks like the timer wasn't getting initialized correctly or was destroyed twice, just need to find out how.

Posted: Wed Dec 10, 2008 4:33 pm
by John Adams
I think this is what you're asking for:
spawnscript:

Code: Select all

function spawn(NPC) 
   --uncomment to require quest 
   --SetRequiredQuest(NPC, 31, 2)
end 
function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end 
function enable_command_icon(NPC, Player) 
   SpawnSet(NPC, "show_command_icon", "1") 
end 
spell:

Code: Select all

function cast(Caster, Target) 
   KillSpawn = GetSpawn(Target, 2530197)
   AddTimer(Target, 1000, "destroy_totem")
   SpawnSet(Target, "destroy_totem", "0") 
   SpawnSet(Target, "show_command_icon", "0") 
end 

Posted: Wed Dec 10, 2008 4:41 pm
by Scatman
Note, you'll want to change the SpawnScript that calls KillSpawn from KillSpawn(Player, NPC) to KillSpawn(NPC, Player). I changed the order the parameters are taken to be consistent with everything else.

Posted: Wed Dec 10, 2008 4:45 pm
by John Adams
Ok Scat, I changed the posted script as you suggested. Please edit or repost whatever else you may see wrong so LE has accurate info.

Posted: Wed Dec 10, 2008 4:53 pm
by LethalEncounter
John Adams wrote:I think this is what you're asking for:
spawnscript:

Code: Select all

function spawn(NPC) 
   --uncomment to require quest 
   --SetRequiredQuest(NPC, 31, 2)
end 
function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end 
function enable_command_icon(NPC, Player) 
   SpawnSet(NPC, "show_command_icon", "1") 
end 
spell:

Code: Select all

function cast(Caster, Target) 
   KillSpawn = GetSpawn(Target, 2530197)
   AddTimer(Target, 1000, "destroy_totem")
   SpawnSet(Target, "destroy_totem", "0") 
   SpawnSet(Target, "show_command_icon", "0") 
end 

One thing I see right away is:

Code: Select all

SpawnSet(Target, "destroy_totem", "0")
That is invalid as the second argument is the parameter you would give /spawn set and there isn't a /spawn set destroy_totem option :)

Posted: Wed Dec 10, 2008 5:33 pm
by John Adams
LE, let me tell ya what we're really after here. KillSpawn() was a necessary add only because we can certainly see needing to kill something remotely :) But I think what we're after with these totems is the ability to "despawn" it after the [destroy totem] command is executed. I believe in live, when you destroy these totems, the player performs a Kick, the totem poofs, and the quest gets updated.
What I do not remember is if there is some other animation that happens - does the totem crumble? fall over? or just vanish? The latter will work for us immediately.
In the end, Despawn() might be the best solution here. I will go try and find the world-crashing bug so at least you can plug that hole, whether the param is right or not, I suppose we shouldn't crash. :)
Edit: here's the crash with the dev svn code:

Code: Select all

>	EQ2WorldDebug.exe!operator delete(void * pUserData=0xdddddddd)  Line 52 + 0x3 bytes	C++
 	EQ2WorldDebug.exe!Timer::`scalar deleting destructor'()  + 0x25 bytes	C++
 	EQ2WorldDebug.exe!ZoneServer::CheckSpawnScriptTimers()  Line 1755 + 0x35 bytes	C++
 	EQ2WorldDebug.exe!ZoneServer::Process()  Line 653	C++
 	EQ2WorldDebug.exe!ZoneLoop(void * tmp=0x083ff860)  Line 2503 + 0x8 bytes	C++
 	EQ2WorldDebug.exe!_callthreadstart()  Line 293 + 0xf bytes	C
 	EQ2WorldDebug.exe!_threadstart(void * ptd=0x08848098)  Line 277	C
 	kernel32.dll!77e64829() 	
 	[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]	

Posted: Wed Dec 10, 2008 6:04 pm
by Scatman
After kicking the totem, you immediately get the update. The totem stays there, untargettable for about 4 seconds then just poofs, no other animation. This is exactly what happens when you /kill the totem, quest updates immediately (using a kill update quest function) after kicking it, totem sits there for a few seconds, then poofs. So killing it would be just as good too I think, otherwise we'd have to figure out how to update the quest if we just de-spawned it?

Posted: Wed Dec 10, 2008 6:06 pm
by John Adams
If there is a delay, just like /kill, then perhaps that's what SOE does. I just assumed it would leave me mystified as the player as to why I just destroyed something that is still lingering around =)
I haven't ran that quest in 6 mos, so it's probably just my foggy memory at play. I'll take Scats word over mine anyday.
(though a Despawn() function would still be nice :p)

Posted: Wed Dec 10, 2008 6:07 pm
by LethalEncounter
OK, I see the problem. Your timer was killing the same spawn that the timer was based on. When a spawn dies it automatically deletes any timers associated it, so when it died it deleted the timer and when your timer finished it tried to delete itself (again). I fixed the code and I'll also add a despawn function. I just finished that quest on live a couple of days ago but I can't remember if they just disappeared or if they did something else first.

Posted: Wed Dec 10, 2008 6:14 pm
by LethalEncounter
BTW if might make it a little more clear if your

Code: Select all

function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end
was

Code: Select all

function destroy_totem(Dead, Killer)
   KillSpawn(Dead, Killer)
end
instead. It performs the same but might give you less headaches when trying to debug something. Feel free to do it as you like, just a thought :) Oh and if you want to use the second parameter to KillSpawn you will need to specify the second spawn in your AddTimer LUA call. It is is 5th parameter in the AddTimer function:

Code: Select all

AddTimer(Spawn, time, function, max count, Spawn)

Posted: Wed Dec 10, 2008 6:17 pm
by John Adams
I'm diggin the whole Dead, Killer thing... adds mystique to our development personas... ;)

Posted: Wed Dec 10, 2008 6:30 pm
by LethalEncounter
heh, btw note that I am adding a few optional parameters:

Code: Select all

KillSpawn(Dead (Spawn), Killer (Spawn), send death packet (0 or 1))
KillSpawnByDistance(Killer (Spawn), distance around (float), include players (0 or 1), send death packets (0 or 1))
Examples:
KillSpawn(NPC, Player, 0) -- player kills NPC but doesnt send death packet or no message in their chat
KillSpawnByDistance(NPC, 10, 1, 1) -- kills everything around the NPC including players, also sends death messages for everything killed
Remember that NPC == Spawn, Player == Spawn, and any name you substitute in place of Spawn is still a Spawn.

Posted: Wed Dec 10, 2008 6:43 pm
by LethalEncounter
OK, I also added Despawn(Spawn, delay). Delay is optional and will be immediate if you leave it off.

Posted: Wed Dec 10, 2008 6:45 pm
by John Adams
Right on, thanks LE!