Difference between revisions of "Compatible Companion Mod Creation/The Fade"
m (Created) |
m (Adding introduction) |
||
Line 1: | Line 1: | ||
− | + | This step fully describes how to give your custom companion their own nightmare and how to control their behaviour in the fade. | |
− | This | + | This tutorial and the gift handling are the hardest. There is so much stuff to do for this, I hope I don't forget anything. If someone tries it sent me message, tell me it worked. Otherwise I forgot something to tell you here probably. So let's take it slow. |
==What we need== | ==What we need== |
Latest revision as of 15:15, 10 July 2011
This step fully describes how to give your custom companion their own nightmare and how to control their behaviour in the fade.
This tutorial and the gift handling are the hardest. There is so much stuff to do for this, I hope I don't forget anything. If someone tries it sent me message, tell me it worked. Otherwise I forgot something to tell you here probably. So let's take it slow.
Contents
What we need
When the PC first enters the fade, there are several important flags and module variables set automatically by the game. The plot resource of interest is CIR300PT_FADE and the flag ENTER_FADE, signals the PC is in Weisshaupt (where he/she meets the fake Duncan). This flag needs to be captured, so build the flag VALERIA_ENTER_FADE, into the NPC plot VALERIA_NPC_HIRE, in order to do this only once. There are three possible nightmares, each for each companion the PC had. We'll make it so our companion goes into the first available one.
We also need to capture the following flags from CIR300PT_FADE: SLOTH_DEMON_ATTACKS (that's the demon that put you to sleep, you fight him at the end of the fade), and SLOTH_DEMON_DEFEATED (when the demon is killed Valeria has to come back to the party, if she didn't help fight the demon).
So create in the plot VALERIA_NPC_HIRE the flags VALERIA_SLOTH_DEMON_ATTACKS, VALERIA_SLOTH_DEMON_DEFEATED (these are so we do it once), as well as, the following important flags for Valeria: VALERIA_HAS_NIGHTMARE_A, VALERIA_HAS_NIGHTMARE_B, VALERIA_HAS_NIGHTMARE_C (these three are to see to which area from the 3 possible Valeria is in)
First add this in includes:
... #include "plt_valeria_fade_nightmare" #include "plt_cir000pt_main" #include "plt_cir300pt_fade" ...
Changes in the function check_plot_changed
Add the following lines in check_plot_changed, to capture important events in the PC's travels in the fade:
//enter the fade, remove valeria from party if (WR_GetPlotFlag(PLT_CIR300PT_FADE,ENTER_FADE) && !WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_ENTER_FADE)) { WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_ENTER_FADE,TRUE); //if she was in the party when the demon put you to sleep, she needs //to have a nightmare area for her if(WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY)) { SetFollowerState(oVal, FOLLOWER_STATE_AVAILABLE); //Adds follower to the active party //this flag is important, it tells us valeria has indeed a nightmare //and will be used in her dialogs(see below) WR_SetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE,VALERIA_SLEEP,TRUE); //which area to put valeria in. these module variables are set when //first entering the fade and are positive if a companion nightmare //area will have an actual companion in it (imagine going there with //only 3 in the party, one area should be inactive, the value -1 //so circle through all 3 and see which one is the first available //the core game scripts would put the other companions already in //one of these, so we just find any available. //so if say Rory(Ser Gilmore) and Valeria are in party, these scripts //are disjoint and they would both behave appropriately //notice how we fill in the first available slot with the companion //I use 50, you should use any other number above 50 to make sure //the vanilla scripts don't think a vanilla companion is occupying //this nightmare area int fol1=GetLocalInt(GetModule(),CIR_FADE_FOLLOWER_1); int fol2=GetLocalInt(GetModule(),CIR_FADE_FOLLOWER_2); int fol3=GetLocalInt(GetModule(),CIR_FADE_FOLLOWER_3); if(fol1<1) { WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_A,TRUE); SetLocalInt(GetModule(),CIR_FADE_FOLLOWER_1,50); // REPLACE THE NUMBER "50" FOR YOUR OWN NUMBER } else if(fol2<1) { WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_B,TRUE); SetLocalInt(GetModule(),CIR_FADE_FOLLOWER_2,50); // REPLACE THE NUMBER "50" FOR YOUR OWN NUMBER } else if(fol3<1) { WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_C,TRUE); SetLocalInt(GetModule(),CIR_FADE_FOLLOWER_3,50); // REPLACE THE NUMBER "50" FOR YOUR OWN NUMBER } } WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY, FALSE);//not in party anymore anyways } /* *************** NUMBERS IN USE: *************** 50 - IDOMENEAS' QUEST & LEGENDS 1140150041 - IMMORTALITY'S SER GILMORE NPC */ //fighting the demon in the fade //after the PC makes it to the inner sanctum, they get to talk to the //demon and the battle begins. This is captured here. Notice that if //we have talked to Valeria in the fade, she should be brought back //to help in battle. if (WR_GetPlotFlag(PLT_CIR300PT_FADE,SLOTH_DEMON_ATTACKS) && !WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_SLOTH_DEMON_ATTACKS) && WR_GetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE, VALERIA_TALKED_TO_IN_FADE)) { WR_SetFollowerState(oVal, FOLLOWER_STATE_ACTIVE); SetImmortal(oVal,0); WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_SLOTH_DEMON_ATTACKS,TRUE); WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY,TRUE); SetLocalInt(oVal, CREATURE_REWARD_FLAGS, 0); //Allows the follower to gain XP SetLocalInt(oVal, AMBIENT_SYSTEM_STATE, 0); SetObjectActive(oVal,1); AddCommand(oVal, CommandJumpToLocation(GetLocation(GetHero()))); //Ensures follower appears at PC's location. } //demon in the fade defeated, this is captured here //if valeria was with the PC when he first entered the fade //she should come back to him regardless of him talking to her in the fade if (WR_GetPlotFlag(PLT_CIR300PT_FADE,SLOTH_DEMON_DEFEATED) && !WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_SLOTH_DEMON_DEFEATED) && WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_SLEEP)) { WR_SetFollowerState(oVal, FOLLOWER_STATE_ACTIVE); WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY,TRUE); WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_SLOTH_DEMON_DEFEATED,TRUE); SetLocalInt(oVal, CREATURE_REWARD_FLAGS, 0); //Allows the follower to gain XP SetLocalInt(oVal, AMBIENT_SYSTEM_STATE, 0); SetObjectActive(oVal,1); AddCommand(oVal, CommandJumpToLocation(GetLocation(GetHero()))); //Ensures follower appears at PC's location. }
The VALERIA_FADE_NIGHTMARE plot, it's journal and script
Another important point, is that the game uses another plot for each companion. So we need to create the plot VALERIA_FADE_NIGHTMARE that will contain similar variables to the corresponding game plot for a companion. Name them: VALERIA_DEMON_HOSTILE, VALERIA_DEMON_KILLED, VALERIA_REALISES_DEMON, VALERIA_RETURNS_TO_PARTY, VALERIA_SLEEP (these have to do with her behavior when we meet her in her nightmare), VALERIA_TALKED_TO_IN_FADE (if we went to Valeria's nightmare and talked her out of it) .
Here is now the script for the plot VALERIA_FADE_NIGHTMARE (in the object inspector for the plot just change the standard plot_core script to this one). I call it: valeria_fade_subplot_script.nss
#include "utility_h" #include "wrappers_h" #include "plot_h" #include "cir_constants_h" #include "cir_functions_h" #include "plt_valeria_fade_nightmare" //this will look weird to you, but it shouldn't really(we're in the //script not the definitions of the flags). when you see below you'll //notice that certain flags from this plot are not set here, they are //handled by global_plot_operations //(just setting the flags to TRUE or FALSE nothing more) #include "plt_valeria_npc_hire" #include "plt_cir300pt_fade" int StartingConditional() { event eParms = GetCurrentEvent(); // Contains all input parameters int nType = GetEventType(eParms); // GET or SET call string strPlot = GetEventString(eParms, 0); // Plot GUID int nFlag = GetEventInteger(eParms, 1); // The bit flag # being affected object oParty = GetEventCreator(eParms); // The owner of the plot table for this script object oConversationOwner = GetEventObject(eParms, 0); // Owner on the conversation, if any int nResult = FALSE; // used to return value for DEFINED GET events object oPC = GetHero(); object oTarg; object oVal = UT_GetNearestCreatureByTag(oPC,"valeria_npc"); plot_GlobalPlotHandler(eParms); // any global plot operations, including debug info if(nType == EVENT_TYPE_SET_PLOT) // actions -> normal flags only { int nValue = GetEventInteger(eParms, 2); // On SET call, the value about to be written (on a normal SET that should be '1', and on a 'clear' it should be '0') int nOldValue = GetEventInteger(eParms, 3); // On SET call, the current flag value (can be either 1 or 0 regardless if it's a set or clear event) // IMPORTANT: The flag value on a SET event is set only AFTER this script finishes running! switch(nFlag) { case VALERIA_DEMON_HOSTILE: { //when we speak to her, we might manage to make her realize she's in a nightmare, or not, //if she realizes she'll help battling the demon pretending to be her sister if(WR_GetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE, VALERIA_REALISES_DEMON) == TRUE) { //Set to friendly SetGroupId(oVal, GROUP_FRIENDLY); WR_SetFollowerState(oVal, FOLLOWER_STATE_ACTIVE); } else { //If Valeria hasn't realised it is a demon set to neutral SetGroupId(oVal, GROUP_NEUTRAL); } //Make Victoria into Incubus //in the nightmare area I've created, 19741 is Victoria, Valeria's dead sister, // and 19742 (initially inactive) is the Demon holding her UT_TeamAppears(19741, FALSE); UT_TeamAppears(19742, TRUE); UT_TeamGoesHostile(19742, TRUE); break; } case VALERIA_RETURNS_TO_PARTY: { WR_SetObjectActive(oVal, FALSE, BASE_ANIMATION_SLEEP, FADE_VFX_TELEPORT); if(WR_GetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE, VALERIA_REALISES_DEMON) == TRUE) { //Set to friendly WR_SetFollowerState(oVal, FOLLOWER_STATE_UNAVAILABLE); // WR_SetFollowerState(oVal, FOLLOWER_STATE_ACTIVE); // WR_SetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE,VALERIA_SLEEP,FALSE); // WR_SetPlotFlag(PLT_VALERIA_NPC_HIRE, PARTY_VALERIA_IN_PARTY,TRUE); } //the nightmare variables are set in the function check_plot_changed(see above), //what we are setting here, are the plot variables that will change the //actual area in the fade map to done. you can see those variables below if (WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_A)) { WR_SetPlotFlag(PLT_CIR300PT_FADE_PORTAL, FADE_PORTAL_GREEN_1_COMPLETE, TRUE, TRUE); } else if (WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_B)) { WR_SetPlotFlag(PLT_CIR300PT_FADE_PORTAL, FADE_PORTAL_GREEN_2_COMPLETE, TRUE, TRUE); } else if (WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_C)) { WR_SetPlotFlag(PLT_CIR300PT_FADE_PORTAL, FADE_PORTAL_GREEN_3_COMPLETE, TRUE, TRUE); } break; } } } else // EVENT_TYPE_GET_PLOT -> defined conditions only { switch(nFlag) { } } plot_OutputDefinedFlag(eParms, nResult); return nResult; }
Forgot(told ye I would). Here's how to add the right journal entries, and also, how to define the plot properties (see the object inspector on the right). Notice this plot has to be a subplot to cir300pt_fade so what we get the correct Journal behavior as well (like the game does). Notice when the quest is done and we set this as the final entry (Final=Yes).
Taking care of Valeria's dialog in her nightmare area
I am using a stage for this, with the appropriate options set in the dialog. I won't go into it. You can do that.
The flags in VALERIA_FADE_NIGHTMARE are important here. Notice the check for the SLEEP flag here. Also notice we only run this dialog once.
Now you can do whatever you want, but I find this approach best. Notice the first of two options, checks to see if the PC has 3 ranks in persuasion. If that happens, Valeria snaps out of it right away.
Now notice how the REALISES_DEMON variable is set, so that Valeria will help in the battle with the demon acting as her sister.
Notice how we set the flag VALERIA_DEMON_HOSTILE in the plot valeria_fade_nightmare (see the script). It will initiate the battle.
Notice that if she's a mage she snaps out of it (second way). Notice how this links back up so we set the flag VALERIA_DEMON_HOSTILE in the plot valeria_fade_nightmare again.
Otherwise, you fight the demon alone. Notice how this links back so we set the flag VALERIA_DEMON_HOSTILE in the plot valeria_fade_nightmare again as we did above.
Set the VALERIA_TALKED_TO_IN_THE_FADE flag (so she'll help in the final demon battle). We show this option only once per game.
Set the VALERIA_RETURNS_TO_PARTY flag (removes Valeria from party). See the valeria_fade_nightmare plot script.
Valeria Nightmare Area specifics
Create a duplicate copy of a game companion nightmare area resource. I call it valeria_fade_nightmare(.are). Mine is using the predefined area layout lak526d for this (similar to Morrigan's nightmare I think, I probably duplicated her nightmare area and edited it). You need to do this so you'll have the fade pedistal in the area and atmosphere sounds, setting etc. You can remove some of the waypoints etc and edit it to what you want the nightmare to be. That's up to you can't help you there. Make sure the entry waypoint is tagged "start".
Set the script of the area to "valeria_nightmare". It's a copy of the core game resource tailored to what we want to do. First here's the area script.
#include "utility_h" #include "party_h" #include "plt_valeria_fade_nightmare" void main() { event evEvent = GetCurrentEvent(); // Event int nEventType = GetEventType(evEvent); // Event Type object oEventCreator = GetEventCreator(evEvent); // Event Creator object oPC = GetHero(); object oParty = GetParty( oPC ); object oThis = OBJECT_SELF; int bEventHandled = FALSE; object oTarg, oFollower; //I pass handling to the standard script first here for things like // polymorphing handling (rat, golem etc), and standard behavior. HandleEvent( evEvent, R"cir000ar_fade_core.ncs" ); switch ( nEventType )//we capture the following events though { case EVENT_TYPE_AREALOAD_PRELOADEXIT: { // When: for things you want to happen while the load screen is // still up, things like moving creatures around. int nIndex; int nArraySize, nSpiritArraySize; int bArcaneFormActive; int bBurningFormActive; int bGolemFormActive; int bMouseFormActive; int bSpiritFormActive; int bPCHasArcaneForm; int bPCHasBurningForm; int bPCHasGolemForm; int bPCHasMouseForm; int bPCHasSpiritForm; object [] arFireBases, arSpiritBases; nArraySize = GetArraySize( arFireBases ); // VALERIA'S NIGHTMARE if ( GetTag(oThis) == "valeria_fade_nightmare" && WR_GetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE,VALERIA_RETURNS_TO_PARTY) == FALSE ) { oFollower = Party_GetFollowerByTag("valeria_npc"); WR_SetObjectActive(oFollower, TRUE); UT_LocalJump(oFollower,"valeria_spot"); //this is the waypoint Valeria appears in the area, so move her there(see pictures) } break; } case EVENT_TYPE_TEAM_DESTROYED: { int nTeamID = GetEventInteger(evEvent, 0); // Team ID if(nTeamID==19742) //capture when the demon dies and talk to Valeria { WR_SetPlotFlag(PLT_VALERIA_FADE_NIGHTMARE,VALERIA_DEMON_KILLED,TRUE); oFollower = Party_GetFollowerByTag("valeria_npc"); UT_Talk(oFollower,oPC); } break; } } }
My setup in the area. I don't know if you can see the inactive (red box) and active (yellow) Victoria versions.
The pedestal.
So you think you're done, think again. Changes in Event Handling
We finally need to capture when the PC selects the right nightmare area (the one area that contains Valeria, it will be loaded appropriately)
Add this in the Event Handling part of the module event script:
case EVENT_TYPE_BEGIN_TRAVEL://EVENT_TYPE_WORLD_MAP_USED: { string sSource = GetEventString(ev, 0); // the area tag the player is travelling from string sTarget = GetEventString(ev, 1); // the area tag the player is travelling to string sWPOverride = GetEventString(ev, 2); //we pick to sent the PC clicking to the right nightmare area here //it's funny actually, all tags for the core game nightmare companion //map pins are given the same value "Fade_Follower". What distinguishes //them is sWPOverride(thank god for that otherwise we'd be in trouble) //if I remember correctly, the companion nightmare areas in the fade //map, go 1,2,3 counterclockwise starting from the one on the left //valeria_fade_nightmare is the name of the area for Valeria's //nightmare, start is the waypoint tag if(sWPOverride=="1" && sTarget=="Fade_Follower" && WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_A)) DoAreaTransition("valeria_fade_nightmare","start"); if(sWPOverride=="2" && sTarget=="Fade_Follower" && WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_B)) DoAreaTransition("valeria_fade_nightmare","start"); if(sWPOverride=="3" && sTarget=="Fade_Follower" && WR_GetPlotFlag(PLT_VALERIA_NPC_HIRE,VALERIA_HAS_NIGHTMARE_C)) DoAreaTransition("valeria_fade_nightmare","start"); break; }
Phew, I hope, I didn't forget anything.