stoffe Posted August 1, 2006 Share Posted August 1, 2006 Hmm, this is hard to explain in an understandable way. I'll do an example to illustrate how I was thinking, since I have no idea what kind of quest you are doing... (I did like this for testing in my game and it seemed to work.) Premise: 4 quest NPCs, each carrying a quest item. Journal updates each time the player picks up a datapad from a fallen NPC. When all 4 datapads are collected the quest is completed. Files involved (all in override: (All items have identical tags and ResRefs for simplicity.) questnpc1.utc (the first NPC) [color=Orange]questitem1.uti[/color] (item carried by [i]questnpc1[/i]) [color=YellowGreen]questchecker1.utp[/color] (placeable spawned on [i]questnpc1[/i]'s death) questchecker_hb1.ncs (heartbeat event script of [i]questchecker1[/i] placeable) death_questnpc1.ncs (OnDeath event script of [i]questnpc1[/i]) questnpc2.utc (the second NPC) [color=Orange]questitem2.uti[/color] (item carried by [i]questnpc2[/i]) [color=YellowGreen]questchecker2.utp[/color] (placeable spawned on [i]questnpc2[/i]'s death) questchecker_hb2.ncs (heartbeat event script of [i]questchecker2[/i] placeable) death_questnpc2.ncs (OnDeath event script of [i]questnpc2[/i]) questnpc3.utc (the third NPC) [color=Orange]questitem3.uti[/color] (item carried by [i]questnpc3[/i]) [color=YellowGreen]questchecker3.utp[/color] (placeable spawned on [i]questnpc3[/i]'s death) questchecker_hb3.ncs (heartbeat event script of [i]questchecker3[/i] placeable) death_questnpc3.ncs (OnDeath event script of [i]questnpc3[/i]) questnpc4.utc (the fourth NPC) [color=Orange]questitem4.uti[/color] (item carried by [i]questnpc4[/i]) [color=YellowGreen]questchecker4.utp[/color] (placeable spawned on [i]questnpc4[/i]'s death) questchecker_hb4.ncs (heartbeat event script of [i]questchecker4[/i] placeable) death_questnpc4.ncs (OnDeath event script of [i]questnpc4[/i]) global.jrl (one new Journal category added, with 4 quest stages) Note: The first/second/third/fourth label for the NPCs do not mean they must be fought in that order, it's just a way of saying there are four encounters, and group together the files used for each encounter. In this case it won't matter in which order the player encounters them and retrieves the datapads. File relations: Each NPC UTC has their death_questnpc* script assigned to their respective OnDeath event slot (the ScriptDeath field if using a GFF editor). Each NPC UTC has their questitem* UTI item added to their inventory, set to droppable. Each questchecker* placeable UTP has their questchecker_hb* script assigned to their Heartbeat event slot (the OnHeartbeat field if using a GFF editor) Important: The UTP files must not have the Static field set, otherwise their scripts won't run. Use "plc_invisible.utp" as a blueprint for making your placeable UTPs. Sequence of events: Player fights and kills one of the NPCs. When the NPC dies their questchecker invisible placeable is spawned. Player loots the questitem from the fallen NPC. The questchecker placeable detects this, updates the journal stage to the next and deletes itself. Repeat for the other 3 NPCs. When all 4 datapads are picked up the quest is moved over to the "Completed" section of the Journal. New addition to global.jrl: ¤ Categories ¤ 117 [i](dynamic if you use a mod installer to modify global.jrl)[/i] ¤ Name = "Capture the Datapads" ¤ PlanetID = -1 ¤ PlotIndex = 1 ¤ Priority = 0 ¤ Tag = "[color=SkyBlue]ST_Q_FindDatapads[/color]" ¤ EntryList ¤ 0 ¤ End = 0 ¤ ID = [color=Pink]10[/color] ¤ XP_Percentage = 0.0 ¤ Text = "I have killed an enemy and found a nice datapad among his possessions." ¤ 1 ¤ End = 0 ¤ ID = [color=Pink]20[/color] ¤ XP_Percentage = 0.0 ¤ Text = "On the body of another fallen enemy I found another nice datapad." ¤ 2 ¤ End = 0 ¤ ID = [color=Pink]30[/color] ¤ XP_Percentage = 0.0 ¤ Text = "Yet another vanquished foe was lugging around a nice datapad. I think I see a pattern here..." ¤ 3 ¤ End = 1 ¤ ID = [color=Pink]40[/color] ¤ XP_Percentage = 1.0 ¤ Text = "I have looted a fourth datapad from the battered remains of an enemy. I think my collection is now complete. Yay!" Script code to compile to death_questnpc1.ncs: void main() { if (!GetIsObjectValid(GetObjectByTag("[color=YellowGreen]questchecker1[/color]"))) { CreateObject(OBJECT_TYPE_PLACEABLE, "[color=YellowGreen]questchecker1[/color]", GetLocation(OBJECT_SELF)); } ExecuteScript("k_ai_master", OBJECT_SELF, 1007); } Script code to compile to death_questnpc2.ncs: void main() { if (!GetIsObjectValid(GetObjectByTag("[color=YellowGreen]questchecker2[/color]"))) { CreateObject(OBJECT_TYPE_PLACEABLE, "[color=YellowGreen]questchecker2[/color]", GetLocation(OBJECT_SELF)); } ExecuteScript("k_ai_master", OBJECT_SELF, 1007); } Script code to compile to death_questnpc3.ncs: void main() { if (!GetIsObjectValid(GetObjectByTag("[color=YellowGreen]questchecker3[/color]"))) { CreateObject(OBJECT_TYPE_PLACEABLE, "[color=YellowGreen]questchecker3[/color]", GetLocation(OBJECT_SELF)); } ExecuteScript("k_ai_master", OBJECT_SELF, 1007); } Script code to compile to death_questnpc4.ncs: void main() { if (!GetIsObjectValid(GetObjectByTag("[color=YellowGreen]questchecker4[/color]"))) { CreateObject(OBJECT_TYPE_PLACEABLE, "[color=YellowGreen]questchecker4[/color]", GetLocation(OBJECT_SELF)); } ExecuteScript("k_ai_master", OBJECT_SELF, 1007); } Script code to compile to questchecker_hb1.ncs: void main() { if (GetIsObjectValid( GetItemPossessedBy(GetFirstPC(), "[color=Orange]questitem1[/color]") )) { AddJournalQuestEntry([color=SkyBlue]"ST_Q_FindDatapads"[/color], [color=Pink]GetJournalEntry("[color=SkyBlue]ST_Q_FindDatapads[/color]") + 10[/color]); RemoveHeartbeat(OBJECT_SELF); DestroyObject(OBJECT_SELF, 0.25, TRUE); return; } else { int bOdd = GetLocalBoolean(OBJECT_SELF, 140); SetLocalBoolean(OBJECT_SELF, 140, !bOdd); if (!bOdd) DelayCommand(1.5, ForceHeartbeat(OBJECT_SELF)); } } Script code to compile to questchecker_hb2.ncs: void main() { if (GetIsObjectValid( GetItemPossessedBy(GetFirstPC(), "[color=Orange]questitem2[/color]") )) { AddJournalQuestEntry([color=SkyBlue]"ST_Q_FindDatapads"[/color], [color=Pink]GetJournalEntry("[color=SkyBlue]ST_Q_FindDatapads[/color]") + 10[/color]); RemoveHeartbeat(OBJECT_SELF); DestroyObject(OBJECT_SELF, 0.25, TRUE); return; } else { int bOdd = GetLocalBoolean(OBJECT_SELF, 140); SetLocalBoolean(OBJECT_SELF, 140, !bOdd); if (!bOdd) DelayCommand(1.5, ForceHeartbeat(OBJECT_SELF)); } } Script code to compile to questchecker_hb3.ncs: void main() { if (GetIsObjectValid( GetItemPossessedBy(GetFirstPC(), "[color=Orange]questitem3[/color]") )) { AddJournalQuestEntry([color=SkyBlue]"ST_Q_FindDatapads"[/color], [color=Pink]GetJournalEntry("[color=SkyBlue]ST_Q_FindDatapads[/color]") + 10[/color]); RemoveHeartbeat(OBJECT_SELF); DestroyObject(OBJECT_SELF, 0.25, TRUE); return; } else { int bOdd = GetLocalBoolean(OBJECT_SELF, 140); SetLocalBoolean(OBJECT_SELF, 140, !bOdd); if (!bOdd) DelayCommand(1.5, ForceHeartbeat(OBJECT_SELF)); } } Script code to compile to questchecker_hb4.ncs: void main() { if (GetIsObjectValid( GetItemPossessedBy(GetFirstPC(), "[color=Orange]questitem4[/color]") )) { AddJournalQuestEntry([color=SkyBlue]"ST_Q_FindDatapads"[/color], [color=Pink]GetJournalEntry("[color=SkyBlue]ST_Q_FindDatapads[/color]") + 10[/color]); RemoveHeartbeat(OBJECT_SELF); DestroyObject(OBJECT_SELF, 0.25, TRUE); return; } else { int bOdd = GetLocalBoolean(OBJECT_SELF, 140); SetLocalBoolean(OBJECT_SELF, 140, !bOdd); if (!bOdd) DelayCommand(1.5, ForceHeartbeat(OBJECT_SELF)); } } While it makes this post look like a christmas tree; I have color coded the different parts to make it a little easier to see how they fit together. * * * All this is, of course, a workaround so that you won't have to modify any of the modules in which these encounters occur. Normally, if you'd be designing new modules from scratch where the encounters occur you'd use the module's Mod_OnAcquirItem event instead to detect when the player picks something up. That would require modifying the module.ifo file and shipping the whole modified module file with your mod, which is extreme overkill (and a source for incompatibilities with other mods) unless you make significant other changes to the module or its contained area, or make your own new module. Using dynamically spawned placeables checking for the player acquiring items instead makes it easier to insert into existing modules without having to modify them directly, and the end result would be essentially the same (though there are a few more scripts and template files involved). Using placeables with a heartbeat script instead of starting a recursive function on the NPCs death also ensures the player can leave the area and return between killing the NPC and picking up the datapad without breaking anything if, for some reason, they decide to do so. Link to comment Share on other sites More sharing options...
Lit Ridl Posted August 2, 2006 Share Posted August 2, 2006 That is a perfect tutorial! I'll try PM T7 to add it! Link to comment Share on other sites More sharing options...
Miltiades Posted August 2, 2006 Author Share Posted August 2, 2006 void main() { if (GetIsObjectValid( GetItemPossessedBy(GetFirstPC(), "questitem1") )) { AddJournalQuestEntry("ST_Q_FindDatapads", GetJournalEntry("ST_Q_FindDatapads") + 10); RemoveHeartbeat(OBJECT_SELF); DestroyObject(OBJECT_SELF, 0.25, TRUE); return; } else { int bOdd = GetLocalBoolean(OBJECT_SELF, 140); SetLocalBoolean(OBJECT_SELF, 140, !bOdd); if (!bOdd) DelayCommand(1.5, ForceHeartbeat(OBJECT_SELF)); } } This heartbeat script is different than the other heartbeat scripts you gave, is it not? Anyway, thanks for the comprehensive explanation. This'll help a lot. Maybe the problems lays with the fact that I changed the +10 in the hb-script to +20 because that was the ID of the journal entry. I'll go check out right away! Edit: Ahem... well, uh, it, uh, didn't work . The first journal entry of the quest I don't get by picking up an item, that only starts with the second journal entry. I don't think there's a problem there. The .utp file has an inventory, do I have to put something in there? Link to comment Share on other sites More sharing options...
stoffe Posted August 2, 2006 Share Posted August 2, 2006 This heartbeat script is different than the other heartbeat scripts you gave, is it not? Huh? Not that I can see. The only thing that differs between the heartbeat scripts of the 4 placeables is the tag of the item they are supposed to check for. Maybe the problems lays with the fact that I changed the +10 in the hb-script to +20 because that was the ID of the journal entry. What you do is you retrieve the current quest stage, and then add enough to it to reach the next quest stage. Since an inactive quest has quest stage 0, 0 + 10 = 10, and the first quest stage in my example had ID 10. The next becomes 10 + 10 = 20, which is the ID of the next quest stage in my example etc... Edit: Ahem... well, uh, it, uh, didn't work . The first journal entry of the quest I don't get by picking up an item, that only starts with the second journal entry. I don't think there's a problem there. I have tested the example in the previous post on my game, and it worked fine there. Without knowing exactly how you have done things there is no way can tell what you have done differently or wrong. The .utp file has an inventory, do I have to put something in there? Uh, what UTP file? UTPs are placeable templates. Those used in my example were based on plc_invisible.utp, which has no model or collision data and is thus completely invisible unless it's made selectable. Those have no inventory as standard. Link to comment Share on other sites More sharing options...
Miltiades Posted August 2, 2006 Author Share Posted August 2, 2006 Huh? Not that I can see. The only thing that differs between the heartbeat scripts of the 4 placeables is the tag of the item they are supposed to check for. No, I mean it's different than the heartbeatscripts of your previous posts. Uh, what UTP file? UTPs are placeable templates. Those used in my example were based on plc_invisible.utp, which has no model or collision data and is thus completely invisible unless it's made selectable. Those have no inventory as standard. Yes, I used plc_invisible.utp and renamed it. But if you open the file, you can select objects to be in its inventory. I guess I don't have to do something with that. Link to comment Share on other sites More sharing options...
Miltiades Posted August 2, 2006 Author Share Posted August 2, 2006 I took some screenshots to show you what I've done. The placeable: The heartbeat script: The questchecker script: The journal file: Link to comment Share on other sites More sharing options...
stoffe Posted August 2, 2006 Share Posted August 2, 2006 I took some screenshots to show you what I've done. (...snip...) Well, the only thing I can see at a quick glance that looks out of the ordinary is that you haven't set the Struct Type value to match the List index for the structs in the EntryList of your quest in global.jrl. They all seem to have the value 0 in your screenshot. Perhaps that is what is causing the problem? Link to comment Share on other sites More sharing options...
Miltiades Posted August 2, 2006 Author Share Posted August 2, 2006 I changed it, but it didn't fix the problem. Link to comment Share on other sites More sharing options...
Miltiades Posted August 3, 2006 Author Share Posted August 3, 2006 Can I make a remark? In one of your previous posts (th large one), you showed how the journal file must look like. The PLanetID is 1, though then the quest would only be on Dxun. I thought -1 was what must be filled in. If what I say is wrong, please tell me. Link to comment Share on other sites More sharing options...
Darkkender Posted August 3, 2006 Share Posted August 3, 2006 Can I make a remark? In one of your previous posts (th large one), you showed how the journal file must look like. The PLanetID is 1, though then the quest would only be on Dxun. I thought -1 was what must be filled in. If what I say is wrong, please tell me. I'm not sure myself but when looking at Stoffe's example with that in it earlier I believe that may be a Boolean data type for PlanetID. However if it's not and it's the actual ID for a Planet then you want to set it with the ID for your first Planet when the Quest begins. If your on Dxun then it starts with a 1. Because the Global.jrl file is a Global file the values set in there are merely initializers that will get updated and changed as you proceed through the game. Everytime the game saves it likely will save changes of your global.jrl which might include a new PlanetID from the last time that your quest got updated. Link to comment Share on other sites More sharing options...
stoffe Posted August 3, 2006 Share Posted August 3, 2006 In one of your previous posts (th large one), you showed how the journal file must look like. The PLanetID is 1, though then the quest would only be on Dxun. I thought -1 was what must be filled in. If what I say is wrong, please tell me. The value in the PlanetID is a line number in the planetary.2da file to which planet your quest is supposed to be associated with. However this has no effect at all on where the quest can be triggered. All the PlanetID field does is determine the name of the planet shown above the quest stage text on the journal screen in the game. So it has no bearing on whether your quest entries appear or not. It's just there to help the player keep track on where they need to be to do the quest. For example, using the above example, with the PlanetID set to 1 the text for the first stage would be shown as: Dxun: I have killed an enemy and found a nice datapad among his possessions. ...on the journal screen in the game. Setting the PlanetID field to the value -1 will disable the planet name above the quest text, which is usually what you'd want for a quest spanning multiple planets. The missing minus character in front of 1 in the above example was a typo. I changed it, but it didn't fix the problem. Hmm... very odd. I don't know what else to suggest as it works fine in my game. I've implemented the above example to make sure I didn't forget something important something this time: I inserted the encounters on Dxun, Dantooine, Nar Shaddaa and Korriban, and my custom journal entry shows up when the first datapad is picked up, is updated when the two others are picked up, and moved to the "Finished" section when the last pad is picked up. Link to comment Share on other sites More sharing options...
Miltiades Posted August 3, 2006 Author Share Posted August 3, 2006 Oh, it does just that, add the name of the planet in the journal entry. Ok then. Yes, I know it's really weird that it doesn't work. I double-checked it a couple of times, made a few changes sometimes, without any luck. I hope I don't need to start from the beginning every time I change something to this quest. The first entry is obtained through dialog, and from there I warped to another module, fought my way through and saved before encountering the NPCs. -Could it be the fact that I work with GFF-editor and not with K-GFF? -Or could it be that it doesn't work because the NPCs on the other planets who are supposed to be killed to get a journal entry only have been placed in their module, and at the moment don't have anything to get a journal entry from? Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.