Hello,
I checked this and it seems to be a bug. I used the following test script (written, so that you should be able to compile and use it too):
(You must change the AI script to a script which exists. It is helpful if the NPCs do not wander around).
Code: Select all
use uo;
use basic;
use os;
use util;
CONST TIMEOUT := 120;
CONST N_NPCS := 2;
program testmobrefdict(who)
var mobiles := dictionary;
var res;
var aborttime := ReadGameClock() + TIMEOUT;
// Create N_NPCS numbered mobiles, they are numbered in the sequence of creation
// Add the MobRefs to the dictionary, in the order of creation
// Using Template of an human male (0x190), and a simple script which does nothing (stone just stands still)
// NPCs are create in a line before you facing N - check if there is space!
// Props - just for the script, and the name
var props := struct {"name", "script"};
props.script := "stone";
for n := 1 to N_NPCS
props.name := "NPC"+CStr(n);
var mob := CreateNpcFromTemplate("N0190", who.x - 1 + n, who.y-2, who.z, props, who.realm);
if (!mob)
syslog("Could not create NPC: "+mob.errortext);
exit;
endif
mobiles.insert(mob, n);
endfor
// Now this waits, until all the NPCs are dead and removed from the dictionary
// TIMEOUT - ends the script forcefully, if something goes wrong
// Time limit TIMEOUT seconds, loop runs every 5 seconds
// When all NPCs are killed, the loop ends, it end forcefully after TIMEOUT seconds even if not empty
while (mobiles.size() > 0)
sleep(4);
print("Keys = "+mobiles.keys());
foreach mob in (mobiles.Keys())
if (!(mob.dead == 0))
syslog("Killed: "+CStr(mobiles[mob]));
res := mobiles.erase(mob);
if (!res)
print(res.errortext);
print(CStr(res));
print("Error with MobRef - not removed!");
endif
else
syslog("Mob exists and is alive: "+CStr(mobiles[mob]));
endif
if (ReadGameClock() >= aborttime)
if (mobiles.size() > 0)
print(mobiles);
syslog("Timeout Testscript: Dictionary not empty");
exit;
endif
endif
endforeach
print(mobiles);
sleep(1);
endwhile
syslog("Script ends normally");
SendSysMessage(who, "Script ended normally");
endprogram
The script is simple: It creates 2 NPCs (N_NPCS can be changed to use more), and it has a timeout TIMEOUT seconds, so that the script is aborted if the dictionary cannot be emptied. Normally the test script stops as soon the dictionary is empty.
The script adds the MobRef of each created NPC to the dictionary, using MobRef as a key, and the creation number (1,...) as value. Then it runs a loop every 5 seconds, printing the dictionary. I also uses the MobRefs to print information, namely the creation number. You can also see the number in the dictionary printouts.
Now - when I kill NPC 1 first, then NPC 2, all seems to be normal. When I kill NPC 2, and then NPC 1, something happens. Here the results from the console:
Example 1: Kill 1, then kill NPC 2
Code: Select all
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 1
dict{ <appobj:MobileRef> -> 2, <appobj:MobileRef> -> 1 }
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 1
dict{ <appobj:MobileRef> -> 2, <appobj:MobileRef> -> 1 }
--- KILL NPC 1
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: 1
dict{ <appobj:MobileRef> -> 2 }
--- KILL NPC2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: 2
dict{ }
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Script ends normally
Example 2: Kill NPC 2, then kill NPC 1
Code: Select all
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: 1
dict{ <appobj:MobileRef> -> 2, <appobj:MobileRef> -> 1 }
--- KILL NPC 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: <uninitialized object>
error{ errortext = "Object does not support members" }
0
Error with MobRef - not removed!
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: <uninit
ialized object>
dict{ <appobj:MobileRef> -> 2, <appobj:MobileRef> -> 1 }
--- THE LOOP STILL TRIES TO REMOVE THE MOBREF, SINCE THE NPC TESTS AS DEAD< AND IT FAILS AGAIN
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: <uninitialized object>
error{ errortext = "Object does not support members" }
0
Error with MobRef - not removed!
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Mob exists and is alive: <uninit
ialized object>
dict{ <appobj:MobileRef> -> 2, <appobj:MobileRef> -> 1 }
--- KILL NPC 1
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: 2
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Killed: <uninitialized object>
error{ errortext = "Object does not support members" }
0
Error with MobRef - not removed!
--- AND NOW THE DICT IS EMPTY, DESPITE THE ERROR MESSAGE, IT REMOVED NPC2 AND REPORTED FAILURE FOR NPC1, BUT IS EMPTY NOW
dict{ }
syslog [scripts/textcmd/gm/poltestmobrefs.ecl]: Script ends normally
As you can see, killing NPC 2 does something to the MobRef2 of NPC 2, so that it becomes unusable (uninit). It also does something to the MobRef1 of NPC1, because I cannot read its value, even if it never was deleted! And the dictionary does not allow to remove MobRef2!
But if I kill NPC1 too, it suddenly is possible to remove MobRef2 (which still reports mob.dead), and a receive the error while removing MobRef1, but it is actually removed, since the dictionary is empty afterwards and the script ends normally.
The same happens with more than 2 NPCs, if you kill them in the order its MobRefs were created an added, removing works normally, but if I start with killing NPC2 or NPC3, things go south. I tried it with 5, but the logs are too long to post here, and there are many variations. But sure is, that if I kill in the same order the NPCs were created and added, it works, else it does not. And it seems, that the dictionary is - despite error messages - empty after killing (and trying to remove) the last NPC.
Interestingly the MobRefs remain valid, since I can test with mob.dead. But dict[MobRef] becomes invalid, so the MobRefs seem to be okay, but the dictionary has a problem somehow.
I hope this helps.
EDIT: I just remembered your request to look at mobiles.keys() - and added a line 'print("Keys = "+mobiles.keys());'. The script above is edited.
This shows (I did not change the results in console in this post): If I kill NPC1, then NPC2, it returns correct mobiles.keys() array, but if I kill NPC2, then NPC1 (the error case), the array seems to become invalid! Before killing a NPC mobiles.keys() is normal, after killing NPC2 (before NPC1) it is no longer printed! It seems to be invaid, and since I read it in every loop pass via mobiles.keys(), it seems to be defective permanently. I just hope, this is not the case with all dictionaries, this would be really bad...
OWH
OWHOrus