I have this problem on one of my chars, and I've read the threads on how to solve it, but now I'm wondering a bit more about it. The Jaroo resurrection solution definitely works, but it has a big XP cost. The console recommendation is similar but also offers a way to recover the lost XP after killing off and resurrecting the character. I was wondering if anyone knows what the technical problem is. I decided to see if there's a way to hack my save game to see if I could fix this, but I couldn't find a way to do it (I started reading the documentation here on MOB structures and tried to see if I could parse a few out of a save game, but didn't have much luck). If one could parse a PC's data, is it likely that this would be as easy as removing some data element (attribute)? I also read that this problem occurs when you change areas while invisible. Is this because some aspect of the spell is tied to the area? I thought I saw a mention of a script hook for transitioning between areas. Maybe it would work to run a script that dispels the party on area transition
The old IE engine certainly has easier data files to figure out LOL. I've been trying to read through the threads on MOB file format to see if I can get a clue as to the save files (.tfaf .tfai). There's supposed to be a utility for unpacking these, but I haven't been able to find it (this link is broken: http://www.co8.org/files/tools/toeeextract.rar). I'm not much good with disassemblers and DLL's. Agetian has a lot of notes on the MOB format, and I'm trying to see if I can parse any of these structures in a save file (this whole pickling thing worries me...).
It shouldn't have any XP cost. It is coded to reset the character's XP to what is was before the death and reincarnation. ToEEextract is for the .dat files, not the saved game files. Still, here is the correct link to it: http://files.co8.org/tools/toeeextract.rar
Hmm, well I'm running with 4.01 of the mod, and I definitely had an XP loss after recovery. I just tried this again with the same result. Maybe it's fixed in the Beta?
The one time I went to Jaroo to remove spell permanency, I had to console the character's XP back to what it was beforehand. I think Jaroo's method makes you lose less XP than killing and raising the character, but it certainly doesn't restore the XP to where it was.
I think I maybe see the problem. This is from Jaroo's dialog. I think the global variable needs to be set before killing the player. Also, is there a reason why the resurrection does occur until the next dialog step? It would be better to do the resurrection there (and do a full heal) unless some kind of delay is needed. Code: {1562}{I will do this free of cost.}{I will do this free of cost.}{}{}{}{kill_picked(picker_obj); game.global_vars[752] = picker_obj.stat_level_get(stat_experience) } I'm not sure why a global variable is used here (I checked and it had no value before I used it). No I had Jaroo do his thing, and my char has only 18000 (big loss!). EDIT: Wait, this won't work. The problem is that the global_vars[752] is used inside the reincarnate script to reset the PC's experience to a lower value (the base for the previous level?). This looks like maybe a co8 fix to the spell. The dialog just needs to use a different global. It would also be good to get rid of the "no thank you" options after the PC is killed. The dialog spreads out the spells (this may be important to do), but I found that it was easy to pick the bale out option by mistake and miss out on Raise and/or XP restore.
Here's a patch to Jaroo's dialog that seems to work: Code: --- 00012jaroo.dlg.bak 2005-09-01 10:13:20.000000000 -0400 +++ 00012jaroo.dlg 2006-06-02 00:10:36.750000000 -0400 @@ -420,17 +420,15 @@ {1048}{Thanks, Jaroo. Good bye.}{}{8}{}{0}{} {1049}{Bye.}{}{-7}{}{0}{} -{1562}{I will do this free of cost.}{I will do this free of cost.}{}{}{}{kill_picked(picker_obj); game.global_vars[752] = picker_obj.stat_level_get(stat_experience) } -{1563}{Okay, great.}{}{8}{}{1575}{npc.cast_spell( spell_reincarnation, picker_obj )} -{1564}{I will have to come back later.}{}{8}{}{0}{} -{1565}{Dat gud.}{}{-7}{}{1575}{npc.cast_spell( spell_reincarnation, picker_obj )} -{1566}{Me go.}{}{-7}{}{0}{} +{1562}{I will do this free of cost.}{I will do this free of cost.}{}{}{}{game.global_vars[753] = picker_obj.stat_level_get(stat_experience); kill_picked(picker_obj); npc.cast_spell( spell_reincarnation, picker_obj ) } +{1563}{Okay, great.}{}{8}{}{1575}{} +{1565}{Dat gud.}{}{-7}{}{1575}{} -{1575}{It is done.}{It is done.}{}{}{}{npc.spells_pending_to_memorized()} -{1576}{I am in need of more healing.}{}{8}{}{370}{picker_obj.stat_base_set(stat_experience, game.global_vars[752])} -{1577}{Need more.}{}{-7}{}{370}{picker_obj.stat_base_set(stat_experience, game.global_vars[752])} -{1578}{Thanks, Jaroo. Good bye.}{}{8}{}{0}{picker_obj.stat_base_set(stat_experience, game.global_vars[752])} -{1579}{Bye.}{}{-7}{}{0}{picker_obj.stat_base_set(stat_experience, game.global_vars[752])} +{1575}{It is done.}{It is done.}{}{}{}{ picker_obj.stat_base_set(stat_experience, game.global_vars[753]); npc.spells_pending_to_memorized() } +{1576}{I am in need of more healing.}{}{8}{}{370}{} +{1577}{Need more.}{}{-7}{}{370}{} +{1578}{Thanks, Jaroo. Good bye.}{}{8}{}{0}{} +{1579}{Bye.}{}{-7}{}{0}{} {10008}{Welcome, my son.}{Welcome, my daughter.}{}{}{}{} {10009}{Greetings, friend.}{Greetings, friend.}{}{}{}{} @@ -446,4 +444,4 @@ {11001}{Your reputation precedes you.}{Your reputation precedes you.}{}{}{}{} {11002}{The Grove provides sanctuary even to one of your sort.}{The Grove provides sanctuary even to one of your sort.}{}{}{}{} {11003}{Your welcome here in the Grove is wearing thin.}{Your welcome here in the Grove is wearing thin.}{}{}{}{} -{11004}{You shall no longer find sanctuary here in the Grove.}{You shall no longer find sanctuary here in the Grove.}{}{}{}{} \ No newline at end of file +{11004}{You shall no longer find sanctuary here in the Grove.}{You shall no longer find sanctuary here in the Grove.}{}{}{}{}
Reincarnate and Raise Dead were fixed by Livonya because they were taking away too much XP (I believe they were setting the character down 2 levels instead of 1.) So that's what that global is probably for.
You are right about 752. Good catch. I did a search for global 753 and came up empty, so I think it should be safe to use it. I think the various steps were spread out for visual effect, but I could be wrong about that. Your changes look good. I'm going to run a few tests, and if they pan out they way I think they will, I will put your changes into 5.0.0.
Okay, great! I can't say I play tested this extensively, but the two times I tried it out it worked great!
I should mention one thing I noticed while playing around with the dialog scripting. I tried putting all the commands in one dialog option but they didn't all get executed. So I did break them up into two dialog lines. I think there must be a maximum number of commands or maximum command line length per a dialog entry.
Livonya also found the maximum command line thing troublesome in the brocken tower fight, IIRC she said the maximum was 3 commands per dialogue line.
I was wondering if it's possible to call other scripts from the dialog. It looks like it might not be too hard to create a spell like script (but I don't know if there are a fixed number of these, I really should look at some of the stuff Livonya has done to see what I can learn). I looked for some documentation on the "game.picker" function. I didn't see any here, and I think I've figued out more-or-less how it works. Let me know what you think: Code: game.picker(operator, spell_name, should_doit_on, [ <not-applicable>, <canceled>, <continue> ]) operator: the object that will perform the requested action on the picked target. This is "npc" in a diaog file. spell_name: a token in spell_enum.mes used to look up the spell name in spell.mes should_doit_on: a function that returns true if the operation should be performed on the picked target [ <not-applicable>, <canceled>, <continue> ] a list of three integer dialog entry points: <not-applicable>: used if "should_doit_on" returns false. <canceled>: used if the selection is canceled. <continue>: used if neither of the other two are. So as an example, in data/dlg/00005calmert.dlg you'll see gamer.picker used like this: Code: game.picker( npc, spell_cure_light_wounds, should_heal_hp_on, [ 290, 320, 350 ] ) 290 is used if "should_heal_hp_on" returns false on the selected party member: "That person does not require this healing at this time." 320 is the parent healing dialog and we go back here if the action is canceled: "What kind of healing do you need?" 350 is used if the action isn't canceled and is valid on the picked party member: "The cost to Cure Light Wounds will be 80 gold pieces"
That sounds about right, except that the "should_heal_hp_on" function (scripted it utilities.py IIRC) checks to make sure the target isn't dead.