Scripting 9 & 12 weeks

Post » Fri May 04, 2012 3:26 am

I've been really struggling in testing the scripts for 9 & 1/2 weeks so in an effort to make some progress I could really use some help

Melian very kindly wrote me a light companion script a year ago and I've been trying it out - the script works well however I sometimes want to try to do some things it can't cope with

For instance the companion will come to a certain place and not want to move from there for a few days - I have localdayspassed as a variable - so in dialogue it tests fine - however getting the companion to stay in one spot has proven difficult

I have a global variable called BM_Maidservice this is set to 1 when she enters into companion mode (btw she has no companion share by design) - I was adding to the script a small section that said if she was set to BM_Maidservice 2 then have a stationary AIwander - this would freeze her in place literally as in she would slightly tremble and there would be no idles working at all - however she would stay put for the whole localdayspassed as set in dialogue - however this would create problems with other scripts where i would want her to do some AITravel in a room if she was in freeze mode the scripts just wouldn't move her.

If in dialogue i just add in the results box AIWander 0 0 0 0 - this is not sufficient as i have observed putting her in wait mode and sometimes she will still follow me. Is there someway I can amend this script so that when my Global is set to 2 she still has normal idles but is locked into position until I rest her via dialogue to 1?

begin illyCompanionLSshort followNow  ;simple check for follow mode - if you have a follow variable                ;that's set from dialogue it would be more reliable so replace this if you have oneshort counter  ; added b/c script is filling up a bit now -                ;  stuff that doesn't need to be done every frame can go at end of scriptshort oldCell  ;type of previous cell, interior=1, exterior=0short curCell  ;type of current cell (as above)short matchZ  ;warp needed on z-axis? for levitation/swimmingshort cmbtChk  ;combat checkshort wwChk  ;do-once for taking waterwalking potionshort swimChk  ;does the cell have water? (if so then will check for swimming)short sick  ;check for disease, 0=healthy 1=common disease 2=blight diseaseshort attrDmgshort doorFix  ;state variable for load-door fixshort doOnce1  ;doonce vars for Grumpy's warping code/save warp destination pointsshort doOnce2short tmpS  ;just a temp var (can use in dialogue results calcs)short storeDay  ;simple day change check for medication once-per-day                    ; - remove this if doing it in dialogue instead;potion storage vars;these will need spells set up to apply the effects, except for;  restore health (which is better done in code alone);spells should all be type ability;to use these in dialogue:;if using one of the NPC's potions (ie one stored in these vars):;check that the relevant variable is > 0 (ie that she's actually got some) and if so:;                       set variable to ( variable - 1 );                       AddSpell "spell ID";                       set cureTmr to 1;(that last line will trigger the script to remove the ability once it's done its job);of course replace placeholder ids with the real idsshort pv_lev  ;levitationshort pv_cureC  ;cure common diseaseshort pv_health  ;restore healthshort pv_wwalk  ;water walkingshort pv_dispel  ;dispel (note: beware mischievous players telling her to take a dispel potion while levitating/waterwalking!)short pv_meds  ;daily medicine (2 associated spells needed for this one: cure blight and restore all attributes)float ax  ;position vars for warpingfloat ayfloat bxfloat byfloat bzfloat cxfloat cyfloat czfloat t1  ;temp vars used in warping codefloat t2  ;these "t*" vars can be reused as temp vars in dialogue results if neededfloat t3float t4float coDist  ;distance checks for warpingfloat coDist2float pcDist  ;distance to player - GetDistance is slow, it's cheaper to check once per framefloat warpTmr  ;time out for warpingfloat wndrTmr  ;time out for wander (door fix etc) - can be used in dialogue eg step aside option;to use a step aside option, put in dialogue results:;               set wndrTmr to 3;               AIWander 1000 0 0 0 0 0 0 0 0 0 0 0;               goodbye;the timer should (I hope) put her back in follow mode when it's done (if she was in follow;  mode to start with)float sheathe  ;timer for weapon sheathing after combat (otherwise sheathing would                ;   trigger when combat target is distant or when switching combat targets)float levTmr  ;levitation time-outfloat cureTmr  ;timer for cure/restore abilities to simulate potion usefloat prevX  ;check for change in x-position - more reliable than cellChangedfloat currXfloat swimLvl  ;used to check if swimmingfloat playZfloat myZ  ;current z-positionfloat tmpF  ;just a temp var (can be used for calcs in dialogue results);heal and restore while sleeping, and;check if NPC is dead/unconscious/paralysed -;no point running the rest if they are!if ( GetHealth < 1 )    returnelseif ( GetPCSleep )  ;I put this before menumode since otherwise the PC    ModCurrentHealth 999  ; has to sleep at least 2 hours for it to trigger    ModCurrentMagicka 999    ModCurrentFatigue 999    returnelseif ( GetPCTraveling )        set doorFix to 1 ;wander to get out of pile-up after fast travel        returnelseif ( MenuMode )    returnelseif ( GetFatigue < 1 )    returnelseif ( GetParalysis > 0 )    returnendifif ( wndrTmr < 500 )elseif ( doorFix != 0 )elseif ( GetCurrentAIPackage == 3 )        set followNow to 1elseif ( GetCurrentAIPackage != -1 )  ;if AI is invalid, this assumes the last valid package        set followNow to 0                              ;is still the correct one        set warpTmr to 0endif;check for cell change - need to know if one or both; cells are interior. This triggers the door-fix wander;Problem is that on game load the x-pos is wrong value first time;  so also check for game load via startscriptset tmpS to 0set prevX to currXset currX to ( GetPos x )set tmpF to ( currX - prevX )if ( doorFix == -1 )  ;just warped, false alarm        set doorFix to 0elseif ( doorFix == 0 )        if ( followNow == 0 )        elseif ( mel_reload == 1 )  ;game load = false alarm        elseif ( tmpF > 512 )                set tmpS to 1        elseif ( tmpF < -512 )                set tmpS to 1        endifendifif ( tmpS >= 1 )        set oldCell to curCell        set curCell to ( GetInterior )        set swimChk to 0        if ( oldCell == 1 )  ;if a cell is interior, do the fix                set doorFix to 1        elseif ( curCell == 1 )                set doorFix to 1        elseif ( tmpS == 1 )  ;this will kick in with e.g. scripted teleports                set doorFix to 1        endifendifset pcDist to ( GetDistance player )set warpTmr to ( warpTmr + GetSecondsPassed )if ( wndrTmr < 500 )        set wndrTmr to ( wndrTmr - GetSecondsPassed )        set warpTmr to 0        if ( wndrTmr <= 0 )                set wndrTmr to 512                if ( followNow == 1 )                        AIFollow player 0 0 0 0                else                        AIWander 256 0 0 30 35 5 10 5 10 5 0 0  ;replace idles and distance with your defaults/whatever you want                endif        endifendifif ( doorFix > 0 )        if ( mel_reload != 0 )  ;if it got past the first check, catch it here                set wndrTmr to 0.1  ;this should hopefully put her back in follow mode                set doorFix to 0                return        elseif ( doorFix > 7 )                if ( wndrTmr > 500 )                        set doorFix to 0  ;all done                        return                endif        elseif ( doorFix == 4 )                if ( pcDist < 800 )  ;don't need to warp                        set doorFix to 6                elseif ( ScriptRunning illy_loaddoorfix == 0 )                        set doorFix to 5                        StartScript illy_loaddoorfix  ;warp companion back to player if she's got lost                endif        elseif ( doorFix == 5 )                if ( pcDist > 800 )  ;wait for script to do its job                        return                elseif ( ScriptRunning illy_loaddoorfix == 0 )                        set doorFix to 6                endif        elseif ( doorFix == 6 )                AIWander 512 0 0 0  ;this also helps get companion out of the post-door pile-up                set wndrTmr to 2                set doorFix to 7        else                set doorFix to ( doorFix + 1 )        endif        set warpTmr to 4        returnendif;remove spell abilities when doneif ( cureTmr >= 0 )        set cureTmr to ( cureTmr + GetSecondsPassed )        if ( cureTmr >= 2 )                set cureTmr to -2                RemoveSpell "illy_cureBlight"                RemoveSpell "illy_restoreAttribs"                RemoveSpell "illy_cureCommon"                RemoveSpell "illy_dispel"        endifendif;check health and run or teleport away if necessary;just remove this block if you don't want itif ( GetHealthGetRatio < 0.25 )    MessageBox "Insert flee-by-teleport message here"    PlaySound3d "swallow"  ;pretend to take a potion    PlaySound3d "mysticism hit"    PositionCell 10 -58 131 0 "Caldera, Shenk's Shovel"  ;change destination as you like    returnelseif ( GetHealthGetRatio < 0.5 )    if ( GetFlee < 90 )        SetFlee 100        MessageBox "Insert flee-by-running message here if you want one"  ;or you could use say for a voice file instead    endifelseif ( GetFlee > 90 )    SetFlee 10  ;change to whatever your default isendif;give her a health potion if health is low;change health percent value to whatever you wantif ( GetHealthGetRatio < 0.7 )        if ( pv_health > 0 )     ;are these going to be Exclusive potions??                set pv_health to ( pv_health - 1 )                PlaySound3d "swallow"                PlaySound3d "restoration hit"                ModCurrentHealth 200  ;if not Exclusive, change this value to match potion total health increase        endifendif;this next part checks for combat so they don't warp in the middle of it;and so can force weapon sheathing afterwards if they get stuck like that;removed spellcast sound checks, so now there's room to put hit checks in same blockif ( cmbtChk )        set warpTmr to -2        set sheathe to ( sheathe - GetSecondsPassed )        if ( GetSoundPlaying "Weapon Swish" )                set sheathe to 5        elseif ( GetSoundPlaying "crossbowShoot" )                set sheathe to 5        elseif ( GetSoundPlaying "bowShoot" )                set sheathe to 5        elseif ( GetSoundPlaying "Health Damage" )                set sheathe to 5        elseif ( GetSoundPlaying "destruction hit" )                set sheathe to 5        elseif ( GetSoundPlaying "frost_hit" )                set sheathe to 5        elseif ( GetSoundPlaying "shock hit" )                set sheathe to 5        elseif ( GetSoundPlaying "alteration hit" )                set sheathe to 5        elseif ( GetSoundPlaying "illusion hit" )                set sheathe to 5        elseif ( GetSoundPlaying "Hand To Hand Hit" )                set sheathe to 5        elseif ( GetSoundPlaying "Hand to Hand Hit 2" )                set sheathe to 5        elseif ( sheathe <= 0 )                set cmbtChk to 0        if ( GetSpellReadied )            cast "mark" player        else            equip "chitin dagger"          ;Change this if your NPC actually has one. You            RemoveItem "chitin dagger" 1   ;  should use a 1-handed weapon they *don't* have        endif                                ;  - otherwise it will remove their real weapon!    endifelseif ( GetWeaponDrawn )        set cmbtChk to 1        set sheathe to 5        set warpTmr to -2elseif ( GetSpellReadied )        set cmbtChk to 1        set sheathe to 5        set warpTmr to -2endif;check for attribute damage;note this isn't all that reliable (but she'll get restored each day regardless so not a big deal)if ( GetEffect sEffectRestoreAttribute )        set attrDmg to 0elseif ( GetEffect sEffectDamageAttribute )        set attrDmg to 1elseif ( attrDmg == 1 )        set attrDmg to 2endifif ( followNow == 1 )        if ( GetForceSneak )                if ( cmbtChk )  ;take her out of sneak mode if in combat                        ClearForceSneak                elseif ( player->GetEffect sEffectInvisibility )                elseif ( player->GetEffect sEffectChameleon )                elseif ( GetPCSneaking == 0 )                        ClearForceSneak                endif        elseif ( cmbtChk )        elseif ( GetPCSneaking == 1 )                ForceSneak  ;sneak when the player is sneaking, except in combat        endif                if ( player->GetEffect sEffectWaterWalking )                if ( wwChk == 1 )                elseif ( pv_wwalk > 0 )                        set pv_wwalk to ( pv_wwalk - 1 )  ;take a waterwalking potion                        set wwChk to 1                        PlaySound3d "swallow"                        PlaySound3d "alteration hit"                        AddSpell "efb_bf_wwalkA"                endif        elseif ( wwChk == 1 )                RemoveSpell "efb_bf_wwalkA"                set wwChk to 0        endif                ;this bit will make her sneak when the player uses chameleon or        ;invisiblity spells - just remove it if you don't want it,        ;it shouldn't affect anything else much                if ( cmbtChk )        elseif ( player->GetEffect sEffectInvisibility )                if ( GetForceSneak == 0 )                        ForceSneak                endif        elseif ( player->GetEffect sEffectChameleon )                if ( GetForceSneak == 0 )                        ForceSneak                endif        endif                ;levitation works on a timer, so she has time to get down        ;after player's levitation runs out        ;note: it's all in follow mode block, so if player tells her to wait        ;while levitating she'll just stay there in the air indefinitely!        ;this can be changed if you want (can add a slowfall ability and get        ;down that way)                if ( player->GetEffect sEffectLevitate == 1 )                if ( levTmr > 1 )                        set levTmr to 1                elseif ( levTmr <= 0 )                        if ( pv_lev > 0 )                                set pv_lev to ( pv_lev - 1 )  ;take a levitation potion                                PlaySound3d "swallow"                                PlaySound3d "alteration hit"                                AddSpell "illy_levitateA"                                set levTmr to 1                        elseif ( GetEffect sEffectLevitate == 0 )  ;in case player casts on her or something                                AIWander 0 0 0  ;don't try to follow if can't levitate                                MessageBox "do you want a warning when she's out of levitation potions??"                        endif                endif        elseif ( levTmr > 10 )                RemoveSpell "illy_levitateA"                set levTmr to 0        elseif ( levTmr > 0 )                set levTmr to ( levTmr + GetSecondsPassed )        endif        elseif ( followNow == 0 )        set warpTmr to 0endifif ( swimChk == 0 )  ;we don't know if there's water in this cell or not        if ( curCell == 0 )  ;exterior always has water                set swimChk to 1        elseif ( GetWindSpeed > 0.001 )  ;interior as exterior                set swimChk to 1        elseif ( GetSoundPlaying "FootWaterLeft" == 1 )  ;in true interiors, can only know if                set swimChk to 1                                                        ;there's water when you've stepped in it        elseif ( GetSoundPlaying "FootWaterRight" == 1 )                set swimChk to 1        elseif ( GetSoundPlaying "DefaultLandWater" == 1 )                set swimChk to 1        endifendif;Grumpy's warping calcsset playZ to ( player->GetPos z )set myZ to ( GetPos z )set ax to ( Player->GetPos x )set ay to ( Player->GetPos y )if ( doOnce1 == 0 )        set bx to ( Player->GetPos x )        set by to ( Player->GetPos y )        set bz to playZ        set doOnce1 to 1endifset t1 to ( ax - bx )set t1 to ( t1 * t1 )set t2 to ( ay - by )set t2 to ( t2 * t2 )set t1 to ( t1 + t2 )set coDist to ( GetSquareRoot t1 )if ( coDist > 360 )        set doOnce1 to 0endifif ( coDist > 180 )        if ( doOnce2 == 0 )                set cx to ( Player->GetPos x )                set cy to ( Player->GetPos y )                set cz to playZ                set doOnce2 to 1        endifendifset t3 to ( ax - cx )set t3 to ( t3 * t3 )set t4 to ( ay - cy )set t4 to ( t4 * t4 )set t3 to ( t3 + t4 )set coDist2 to ( GetSquareRoot t3 )if ( coDist2 > 360 )        set doOnce2 to 0endif;the actual warping bitif ( warpTmr > 6 )        if ( pcDist > 680 )                if ( coDist > 350 )                        set doorFix to -1                        set warpTmr to 0                        SetPos x bx                        SetPos y by                        SetPos z bz                        AIFollow Player 0 0 0 0                        return                elseif ( coDist2 > 350 )                        set doorFix to -1                        set warpTmr to 0                        SetPos x cx                        SetPos y cy                        SetPos z cz                        AIFollow Player 0 0 0 0                        return                endif        endifendifif ( cmbtChk != 0 )elseif ( doorFix != 0 )elseif ( followNow == 0 )elseif ( wndrTmr < 500 )elseif ( GetEffect sEffectLevitate )  ;check geteffect again in case the pc casts on her        set matchZ to 1elseif ( swimChk == 1 )        set swimLvl to ( ( GetWaterLevel ) - 119.7 )  ;check if actually *in* the water, not just wading        if ( myZ <= swimLvl )   ;we're swimming                set swimLvl to ( swimLvl - 12 )                set tmpF to ( swimLvl - 20 )                if ( myZ <= swimLvl )   ;companion is underwater                        set matchZ to 1                elseif ( playZ < tmpF ) ;player underwater                        set matchZ to 1                endif        endifendif;this bit moves the companion gradually towards the player's z-axis position;still has same issue as Grumpy's companions in that it can't detect collision;so can end up stuck in stairs etc - but that fixes itself soon enoughif ( matchZ == 1 )        set matchZ to 0        set tmpF to ( myZ - playZ )        if ( tmpF != 0 )                if ( tmpF >= 5 )                        set myZ to ( myZ - 5 )                elseif ( tmpF <= -5 )                        set myZ to ( myZ + 5 )                else                        set myZ to playZ                endif                SetPos z myZ        endifendifif ( cmbtChk == 1 )        set counter to 0        returnelseif ( counter < 20 )            ;  ---------- COUNTER ----------        set counter to ( counter + 1 )        returnendifset counter to 0if ( GetPCCell "cell where you want potions to restock" )  ;need to add id here!; or if you prefer dialogue for this just delete the block; all the if-checks are in case you ever want to set the vars higher; this way they won't be reduced, only increased    if ( pv_lev < 3 )        set pv_lev to 3    endif    if ( pv_cureC < 3 )        set pv_cureC to 3    endif    if ( pv_health < 3 )        set pv_health to 3    endif    if ( pv_wwalk < 3 )        set pv_wwalk to 3    endif    if ( pv_dispel < 3 )        set pv_dispel to 3    endif    if ( pv_meds < 5 )        set pv_meds to 5    endifendif;in theory Day should be less accurate here than DaysPassed; - but Day doesn't require any particular master file (don't know; if this is tribunal-dependent?); - plus the inaccuracy is very unlikely to happen, and the player probably; won't notice even if it does!if ( pv_meds == 0 )    ;don't do anything yet - this will let her take a potion as soon as she gets oneelseif ( storeDay != Day )    set storeDay to Day    set pv_meds to ( pv_meds - 1 )    AddSpell "illy_cureBlight"  ;placeholder ids    AddSpell "illy_restoreAttribs"    set cureTmr to 1    if ( pv_meds == 1 )        MessageBox "insert message warning player there's only 1 dose left"    endifendifif ( GetEffect sEffectCorpus )  ;note that GetBlightDisease will return true before GetEffect can detect corprus    RemoveEffects 132  ;effect ID for corprus - this needs testing btw, might have to use an ability-type spell instead        set sick to 0                   ;   (note: if the above doesn't work, SfD will need updating!)elseif ( sick == 2 )    if ( ( GetJournalIndex "cure quest ID" ) >= value )  ;PLACEHOLDER - assuming here that cure quest (if you do one) will have a journal        AddSpell "illy_cureBlight"  ;placeholder ID, change as you like        set cureTmr to 1    endif   ;assuming nothing should be done here otherwise? (wait for daily medicine dose?)elseif ( sick == 1 )    if ( pv_cureC > 0 )        set pv_cureC to ( pv_cureC - 1 )        PlaySound3d "swallow"        PlaySound3d "restoration hit"        AddSpell "illy_cureCommon"  ;another placeholder ID        set cureTmr to 1            ;   all these spells should all be type ability    endifendif;disease check - can be dealt with in script or dialogue or both as you likeif ( GetBlightDisease )    set sick to 2elseif ( GetCommonDisease )    set sick to 1else    set sick to 0endif;these are in case your NPC goes swimming - NPCs are too;stupid to keep their heads above water :P;acrobatics is mostly for teleport doors - prevents damage if NPC is slowfalling etcif ( GetWaterBreathing != 1 )    SetWaterBreathing 1endifif ( GetAcrobatics < 199 )    SetAcrobatics 200endifModCurrentFatigue 10  ;companions run a lot while in follow mode, this keeps their                                                ;fatigue up (but won't take effect in combat);emergency warp straight to player position;should only happen when there's no valid warp point storedif ( followNow == 0 )elseif ( pcDist > 1024 )        if ( warpTmr > 9 )                set doorFix to -1                SetPos x ax                SetPos y ay                SetPos z playZ                AIFollow player 0 0 0 0                return        endifendifend
User avatar
sharon
 
Posts: 3449
Joined: Wed Nov 22, 2006 4:59 am

Post » Fri May 04, 2012 5:34 am

to enter default wander mode, try
set followNow to 0
to enter back follow mode, try
set followNow to 1

by the way, you should set this section to proper quest id and numeric value as intended or keep it commented else it will not compile/may cause problems
elseif ( sick == 2 )	; commented until ready /abot if ( ( GetJournalIndex "cure quest ID" ) >= value )  ;PLACEHOLDER - assuming here that cure quest (if you do one) will have a journal		; AddSpell "illy_cureBlight"  ;placeholder ID, change as you like		; set cureTmr to 1	; commented until ready /abot endif   ;assuming nothing should be done here otherwise? (wait for daily medicine dose?)
User avatar
CYCO JO-NATE
 
Posts: 3431
Joined: Fri Sep 21, 2007 12:41 pm

Post » Fri May 04, 2012 5:58 am

to enter default wander mode, try
set followNow to 0
to enter back follow mode, try
set followNow to 1

by the way, you should set this section to proper quest id and numeric value as intended or keep it commented else it will not compile/may cause problems
elseif ( sick == 2 )	; commented until ready /abot if ( ( GetJournalIndex "cure quest ID" ) >= value )  ;PLACEHOLDER - assuming here that cure quest (if you do one) will have a journal		; AddSpell "illy_cureBlight"  ;placeholder ID, change as you like		; set cureTmr to 1	; commented until ready /abot endif   ;assuming nothing should be done here otherwise? (wait for daily medicine dose?)

Hello Abot - thank you for dropping by

I have had eactly as you suggested except the variable follownow was changed to the global BM_Maidservice - this got away from issues with other companions and quests that use the follownow variable

This is melian's orginal message to me

Sorry for the late reply - I'm on slow internet for a while

If you use a follow global, that would be good to use in the script too (more reliable than checking AI package). You could just set the global from dialogue results, and replace the followNow variable in the script with the global, since that's what it's trying to work out (whether or not she's supposed to be following).

This bit won't be needed if you use a global:
if ( wndrTmr < 500 )
elseif ( doorFix != 0 )
elseif ( GetCurrentAIPackage == 3 )
set followNow to 1
elseif ( GetCurrentAIPackage != -1 ) ;if AI is invalid, this assumes the last valid package
set followNow to 0 ;is still the correct one
set warpTmr to 0
endif


But you'll need to reset the warp timer if she's not in follow mode, something like this needs to be in the script somewhere instead:
if ( follow_global == 0 )
set warpTmr to 0
endif


Actually, now that I think about it... "followNow" wasn't such a good idea for the variable id, because it's used by nearly all vanilla followers (all except Rabinna, I think?), so mods use it to identify followers for things (which you may not want done).

I use this global for other features such as enabling clones of her at specific times - when a clone is enabled the original companion is sent to a holding cell so I need to make sure she doesn't warp back to me.

So I had added another section which said

If ( BM_Maidservice == 2 )
Aiwander 0 0 0 30 .... (can't remember the actual idles)
endif

This would lock her in place but then i can't do anything else with her

As for the bit of the script at the end - yes that is well cleaned with the right ids - I posted the original script as given to me by Melian

EDIT: Woohoo!!! I fixed it (well it looks like i have)

I've added a condition to her script that goes

if ( BM_Maidservice != 1 )    if ( GetCurrentAIPackage == 3 )        AIWander 0 0 0 30 35 5 10 5 10 5 0 0         set warpTimer to 0    endifendif

Now she is not doing the paralyzed shivers and hasn't followed me when the global is set to anything but 1

It's hard to express how relieved I feel - maybe there is an emoticon ^_^
User avatar
Lizs
 
Posts: 3497
Joined: Mon Jul 17, 2006 11:45 pm

Post » Fri May 04, 2012 10:54 am

A single character difference in a script can break or fix it. If you want a script fixed, post it, not something similar.
User avatar
Skivs
 
Posts: 3550
Joined: Sat Dec 01, 2007 10:06 pm

Post » Fri May 04, 2012 12:03 am

A single character difference in a script can break or fix it. If you want a script fixed, post it, not something similar.

My apologies Abot - I should have posted the current script - I was trying to address the freezing issue not anything else in the script.

Here is the next script that is not working - I have a few similar to this so I suspect if I can get this right I will be able to fix the others as well.

In a number of places the companion stops and spends a few days - I want them to be on a mini schedule for just a few days cycling them between buildings or NPC's

This script gets to state 3 and then stalls I can't seem to get the AITravel to work?

begin BM_Halfway; Script by Illuminiel; Self terminating Global script begun from Fleur's dialogue; short BM_BalDay	; Global for counting days for Fleur in Balmora but we'll reuse it here; short BM_BalDays_left	; Global for count downshort scriptdayshort setupshort stateshort myhellofloat timeoutfloat timerif ( setup == 0 )	set BM_BalDay to Day	set setup to 1	set BM_BalDays_left to 4			endifendifif ( MenuMode == 1 )	Returnendifif ( "BM_FLeur"->GetHealth == 0 )	stopscript BM_Halfway	returnendifif ( GetJournalIndex, "BM_Tour" == 7 )	set BM_BalDays_left to 0	stopscript BM_Halfway	returnendifif ( setup == 1) 		if ( BM_BalDay != Day )		if (scriptday != Day )			set BM_BalDays_left to ( BM_BalDay - 1 )			set scriptday to Day		endif	endifendifif ( Player->GetDistance "BM_Fleur" < 5000 )    if ( GetCurrentAIPackage == -1 )        set timeout to ( timeout + GetSecondsPassed )        if ( timeout >= 3 )            set state to ( state - 1 ) ; stall occurs at AIPAckageDone - re-issue AITravel            set timeout to 0        endif    else        set timeout to 0    endifelse    set state to 3 ; give up and move to next stependifif ( BM_BalDays_left == 3 )	if ( state == 0 )			if ( GameHour >= 18 )			set state to 1			set myhello to ( GetHello )			SetHello 0		endif	elseif ( state == 1 )		if ( timer < 0.3 )			set timer to ( timer + GetSecondsPassed )			return		endif		set timer to 0		"BM_Fleur"->AiTravel 512 280 268 0 		set state to 2	elseif ( state == 1 )		if ( GetAiPackageDone == 1 )			set state to 3		endif	elseif ( state == 3 )		"BM_Fleur"->positionCell 756 508 260 16200 "Pelagiad, Halfway Tavern"		SetHello myhello		set state to 4		endifelseif ( BM_BalDays_left == 2 )	if ( GameHour >= 18 )		if ( state == 7 )			"BM_Fleur"->positionCell 756 508 260 16200 "Pelagiad, Halfway Tavern"			set state to 8		endif			elseif ( GameHour >= 11 )		if ( GameHour < 18 )			if ( state == 6 )				"BM_Fleur"->PositionCell 2757 152 144 16200 "Pelagiad, Fort Pelagiad"				set state to 7			endif		endif	elseif ( Gamehour < 11 )		if ( GameHour >= 9 )			if ( state == 5 )				"BM_Fleur"->PositionCell 513 -497 771 0 "Pelagiad, Mebestien Ence: Trader"				set state to 6			endif			endif		elseif ( Gamehour < 9 )		if ( state == 4 )			set state to 5		endif		endifelseif ( BM_BalDays_left == 1 )	if ( state == 8 )		"BM_Fleur"->positionCell 375 233 0 330 "Pelagiad, Halfway Tavern"		set state to 9	endifendifend
User avatar
Quick draw II
 
Posts: 3301
Joined: Thu Nov 08, 2007 4:11 pm

Post » Fri May 04, 2012 10:41 am

Pay attention to elseif conditions, they are efficient because they are mutually exclusive.
Some changes I'd try
begin BM_Halfway; Script by Illuminiel; Self terminating Global script begun from Fleur's dialogue; short BM_BalDay       ; Global for counting days for Fleur in Balmora but we'll reuse it here; short BM_BalDays_left ; Global for count downshort scriptdayshort setupshort stateshort myhellofloat timeoutfloat timerif ( setup == 0 )	set BM_BalDay to Day	set setup to 1	set BM_BalDays_left to 4                endif; /fixed /abot endifif ( MenuMode == 1 )	Returnendif; if ( "BM_FLeur"->GetHealth == 0 )if ( "BM_FLeur"->GetHealthGetRatio < 0.04 )  ; may be safer	stopscript BM_Halfway	returnendifif ( GetJournalIndex, "BM_Tour" == 7 )	set BM_BalDays_left to 0	stopscript BM_Halfway	returnendifif ( setup == 1 )  ; added space before bracket        	if ( BM_BalDay != Day )		if ( scriptday != Day )  ; added space after bracket			set BM_BalDays_left to ( BM_BalDay - 1 )			set scriptday to Day		endif	endifendif; if ( Player->GetDistance "BM_Fleur" < 5000 )	; if ( GetCurrentAIPackage == -1 )		; set timeout to ( timeout + GetSecondsPassed )		; if ( timeout >= 3 )			; set state to ( state - 1 ) ; stall occurs at AIPAckageDone - re-issue AITravel			; set timeout to 0		; endif	; else		; set timeout to 0	; endif; else	;set state to 3 ; give up and move to next step;endifif ( BM_BalDays_left == 3 )	if ( state == 0 )       		if ( GameHour >= 18 )			set state to 1			set myhello to ( GetHello )			SetHello 0		endif	elseif ( state == 1 )		if ( timer < 0.3 )			set timer to ( timer + GetSecondsPassed )			return		endif		set timer to 0		"BM_Fleur"->AiTravel 512 280 268 0 		set state to 2	elseif ( state == 2 )   ; elseif (state == 1 ) block was never executed as you had a previous elseif with same condition		if ( GetAiPackageDone == 1 )			set state to 3		endif	elseif ( state == 3 )		"BM_Fleur"->positionCell 756 508 260 16200 "Pelagiad, Halfway Tavern"		SetHello myhello		set state to 4  	endifelseif ( BM_BalDays_left == 2 )	if ( GameHour >= 18 )		if ( state == 7 )			"BM_Fleur"->positionCell 756 508 260 16200 "Pelagiad, Halfway Tavern"			set state to 8		endif           	elseif ( GameHour >= 11 )		if ( GameHour < 18 )			if ( state == 6 )				"BM_Fleur"->PositionCell 2757 152 144 16200 "Pelagiad, Fort Pelagiad"				set state to 7			endif		endif	elseif ( Gamehour < 11 )		if ( GameHour >= 9 )			if ( state == 5 )				"BM_Fleur"->PositionCell 513 -497 771 0 "Pelagiad, Mebestien Ence: Trader"				set state to 6			endif   		endif   	elseif ( Gamehour < 9 )		if ( state == 4 )			set state to 5		endif   	endifelseif ( BM_BalDays_left == 1 )	if ( state == 8 )		"BM_Fleur"->positionCell 375 233 0 330 "Pelagiad, Halfway Tavern"		set state to 9	endifendifend
User avatar
Jimmie Allen
 
Posts: 3358
Joined: Sun Oct 14, 2007 6:39 am

Post » Fri May 04, 2012 12:46 am

Thank you abot - i swear i suffer from scripting dyslexia - I went over those states so many times - I can't believe I didn't see it doubled

Can I ask why you commented out the stall section please - I added that because in the MWSFD it said there were often problems with AITravel if you rest or leave the room
User avatar
Nick Tyler
 
Posts: 3437
Joined: Thu Aug 30, 2007 8:57 am

Post » Fri May 04, 2012 2:07 am

Can I ask why you commented out the stall section please - I added that because in the MWSFD it said there were often problems with AITravel if you rest or leave the room
To temporarily exclude something possibly changing state to 3 while checking the elseif fix. If you find the fixed elseif now working, try removing comments from the stall section.
User avatar
StunnaLiike FiiFii
 
Posts: 3373
Joined: Tue Oct 31, 2006 2:30 am

Post » Fri May 04, 2012 10:40 am

Thanks abot for the explanation.

I have a question about PositionCell - after a NPC is moved around using PositionCell - I have a vague recollection it is best to put them into AIWander for a moment - is that right? The reason I ask is that I'm having some problems with my NPC - after I shift her around a few times I enter into dialogue with her - there is a choice to teleport somewhere together using a different script (which previously worked) but this script is stalling on me now and I just wondered if I needed to let her go into wander mode first?
User avatar
krystal sowten
 
Posts: 3367
Joined: Fri Mar 09, 2007 6:25 pm

Post » Fri May 04, 2012 9:27 am

IIRC the first thing to try is to put her in wander mode before teleporting
so, save current AI state somewhere, and restore it after teleporting is done
short aipset aip to GetCurrentAIPackageaiwanderpositioncellif ( moved)   if ( aip == 3 )    aifollow  endifendif
User avatar
Phillip Brunyee
 
Posts: 3510
Joined: Tue Jul 31, 2007 7:43 pm

Post » Fri May 04, 2012 1:12 am

Firstly - thank you so much for your help so far Abot - I do appreciate it

I found I was having problems running the script from greetings - this has happened a few times to me so once I move the startscript to a topic I get the script to work okay as in it does what it is supposed to

However the problem i am having is when we transport together Fleur is not rendered correctly - she is missing an arm her face and her clothes are a bit transparent and honestly looks unattractive - is there some way i can adjust this script to get her to look correct?

begin BM_Lake ;started from dialogue;based on an original script by Melian, fiddling by Illuminielshort stateshort myhellofloat timerfloat mxfloat myfloat mzfloat maif ( MenuMode == 1 )	returnendifif ( state == 0 )	AddItem BM_weight 1	PlaceAtMe BM_marker1 1 21.15 0	set state to 1elseif ( state == 1 )	if ( timer < 0.3 )		set timer to ( timer + GetSecondsPassed )		return	endif	set timer to 0	set mx to mel_testx	set my to mel_testy	set mz to mel_testz	set ma to mel_testa	player->SetPos x mx	player->SetPos y my	player->SetPos z mz	player->SetAngle z ma	set state to 2elseif ( state == 2 )	if ( timer < 0.3 )		set timer to ( timer + GetSecondsPassed )		return	endif	set timer to 0	RemoveItem BM_weight 1	set myhello to ( GetHello )	SetHello 0	FadeOut 2.0	set state to 3elseif ( state == 3 ) ; previous section just moves her closer for teleporting just for rp purposes 	if ( timer < 2.0 ); same time as fade		set timer to ( timer + GetSecondsPassed )		return  	endif	set timer to 0    	playsound "mysticism area"	Player->Position 12930 -34883 828 222 	"BM_Fleur"->Position 12930 -34903 828 0 	ChangeWeather "Ascadian Isles Region" 0	"BM_Fleur"->AIWander 256 0 0 30 35 5 10 5 10 5 0 0 ; attempt to get her to render 	set state to 4elseif ( state == 4 )	FadeIn 2.0	AddItem BM_weight 1	PlaceAtMe BM_marker1 1 20.12 0	set state to 5elseif ( state == 5 )	if ( timer < 2.0 )		set timer to ( timer + GetSecondsPassed )		return	endif	set timer to 0	set mx to mel_testx	set my to mel_testy	set mz to mel_testz	set ma to mel_testa	player->SetPos x mx	player->SetPos y my	player->SetPos z mz	player->SetAngle z ma	set state to 6elseif ( state == 6 )	if ( timer < 0.3 )		set timer to ( timer + GetSecondsPassed )		return	endif	set timer to 0	ToggleMenus	DisablePlayerControls	ToggleVanityMode	"BM_Fleur"->AIWander 0 0 0 0 0 0 0 0 0 0 0 100 ; custom animation	set state to 7elseif ( state == 7 )	if ( timer < 20 ) ; animation length		set timer to ( timer + GetSecondsPassed )		return	endif	set timer to 0	EnablePlayerControls	ToggleMenus	ToggleVanityMode	RemoveItem BM_weight 1	SetHello myhello	"BM_Fleur"->AIWander 0 0 0 30 35 5 10 5 10 5 0 0	set state to 8elseif ( state == 8 )	StopScript BM_Lakeendifend
User avatar
Julie Serebrekoff
 
Posts: 3359
Joined: Sun Dec 24, 2006 4:41 am

Post » Thu May 03, 2012 10:36 pm

Haven't looked over your script completely just thought I would post a small suggestion. I would recommend using increments of 5-10 when using the State technique. This way you can easily add something without having to change every single else if statement from that point on.

EDIT~~~~~~

As for rendering the NPC properly, does the NPC use any external body mods (Better Bodies, Better Heads, etc.) if so I would suggest making the script without those then add them in after you know the script works just to make sure that the script isn't causing the render problem as it could very well be Better Bodies or whatever your replacer is. Then again it could be a problem with your animation.
User avatar
Lexy Dick
 
Posts: 3459
Joined: Mon Feb 12, 2007 12:15 pm

Post » Fri May 04, 2012 12:45 am

I'd try using positioncell instead of position, http://wryemusings.com/LCV.html#TechnicalNotes
For instance
PositionCell 12930 -34903 828 0 "Balmora"
instead of
"BM_Fleur"->Position 12930 -34903 828 0
You can use any existing exterior cell as "dummy" destination for positioncell, only coordinates really counts.
Also a section like this after teleporting may help fixing AI/visual glitches
	if ( GetFlying > 0 )	elseif ( GetEffect sEffectWaterWalking )	else		disable ; reset visibility		enable	endif	if ( GetCurrentAIPackage == -1 )		StartCombat player		StopCombat	endif
User avatar
Stephanie Valentine
 
Posts: 3281
Joined: Wed Jun 28, 2006 2:09 pm

Post » Thu May 03, 2012 11:38 pm

Thanks abot - I knew i had read something about the difference between position and positioncell before but couldn't find it anywhere in MSFWD - wrye's musing's was exactly what I was after - hadn't read that for a while - as soon as i switched to positioncell the issue went away.
User avatar
Sabrina Steige
 
Posts: 3396
Joined: Mon Aug 20, 2007 9:51 pm

Post » Thu May 03, 2012 10:00 pm

I would like to have a time related quest that has to be done within 6 game hours

However I can't figure out how best to do this

I know how to do a quest which checks for days passing - but hours is harder - In the quest the player could take a travel option by ship - the travel time occurs but I have no way to track it - as in I can work out how to store the 6 hours and make use a simple formula of

If ( BM_Hour != GameHour )
set BM_Hours_left to ( BM_Hours_left - 1 )
set BM_Hour to GameHour
endif

So every time GameHour changes, it triggers a reduction in the BM_Hours_left

However I think that will get messed up in the travel as the engine probably is hard coded to add a GameHour + 4 or whatever for the travel route - which in my script it would only recognise that the BM_Hour no longer = GameHour and would only subtract a single hour from my running total not 4 hours for the travel.

There is the annoying pilgrim quest which is set for floating a timer for > 720 and in the comments it says 12 minutes - I am assuming that means 12mins real time for a gamer but I can't work out what the unit of time for 5 hours would be.

Also if the player saves the game during the quest will that mess up the timer?

If anyone has seen some good scripts on time based quests or can think of a way to do this it would be much appreciated

Thanks
User avatar
Emily Jeffs
 
Posts: 3335
Joined: Thu Nov 02, 2006 10:27 pm

Post » Fri May 04, 2012 12:34 pm

However I think that will get messed up in the travel as the engine probably is hard coded to add a GameHour + 4 or whatever for the travel route - which in my script it would only recognise that the BM_Hour no longer = GameHour and would only subtract a single hour from my running total not 4 hours for the travel.
Well, in this case you don't use a counter of hours but set a fixed expiry time and compare current time with it. Something like this:

if ( doOnce == 0 )
set doOnce to 1
set ExpiryDay to Day
set ExpiryHour to GameHour + 6
if ( ExpiryHour >= 24 )
set ExpiryDay to ExpiryDay + 1
set ExpiryHour to ExpiryHour -24
endif
endif

...
if ( ExpiryDay > Day )
Journal MyQuest, 100
elseif ( ExpiryDay == Day )
if ( ExpiryHour >= GameHour )
Journal MyQuest, 100
endif
endif

There is the annoying pilgrim quest which is set for floating a timer for > 720 and in the comments it says 12 minutes - I am assuming that means 12mins real time for a gamer but I can't work out what the unit of time for 5 hours would be.
I don't quite understand the problem you're facing, but the TimeScale global has seconds-per-second ratio of game's time that you can use. Some players prefer pace-changing mods that increase game day's length; using this variable assures that you provide correct period for your quest regardless of individual players' preferences.
User avatar
matt
 
Posts: 3267
Joined: Wed May 30, 2007 10:17 am

Post » Fri May 04, 2012 9:33 am

Thanks Kir

I have a script which Melian wrote for me that I am trying to adapt

It starts from an NPC's dialogue and as it fires through the various actions it forces the actor to temporarily be quiet

Here's how it goes

short myhello

if ( state == 0 )
set myhello to ( GetHello )
SetHello 0

However what I want to happen in one instance is for the NPC who begins the script to disappear and a clone replace them - this is because they both have different animations that are not merged and it the only way I can handle this

For the clone I want the SetHello 0 to apply to them so how do I write that? is it ActorId.SetHello 0 or ActorID-> SetHello 0 or something else ?
User avatar
Lory Da Costa
 
Posts: 3463
Joined: Fri Dec 15, 2006 12:30 pm

Post » Thu May 03, 2012 10:17 pm

ActorID-> SetHello 0.
User avatar
James Shaw
 
Posts: 3399
Joined: Sun Jul 08, 2007 11:23 pm

Post » Fri May 04, 2012 7:08 am

I'm having problems in testing a script - sometimes it works other times it doesn't - I need to set a Global variable to either 1 or 0 - this is used in dialogue filtering

What is supposed to happen is that when the companion is near the Global BM_Withme is set to 1 and when the companion is not in range it gets set back to 0

How I have written it at the moment is

Begin my_script

float nearme

set nearme to ( Player GetDistance "BM_Fleur" )

if ( nearme > 600 )
if ( BM_Withme == 1 )
set BM_Withme to 0
endif
elseif ( nearme <= 600 )
if ( BM_Withme == 0 )
set BM_Withme to 1
endif
endif
end

Any idea what I am doing wrong?
User avatar
Yung Prince
 
Posts: 3373
Joined: Thu Oct 11, 2007 10:45 pm

Post » Fri May 04, 2012 3:20 am

When you are using the GetDistance function, is the "->" optional? I'd try this:

Begin my_scriptfloat nearmeset nearme to ( Player -> GetDistance "BM_Fleur" )if ( nearme > 600 )  if ( BM_Withme == 1 )    set BM_Withme to 0  endifelse  if ( BM_Withme == 0 )    set BM_Withme to 1  endifendifend
User avatar
Nichola Haynes
 
Posts: 3457
Joined: Tue Aug 01, 2006 4:54 pm

Post » Fri May 04, 2012 10:15 am

If this is for some sort of telepathy ring, I'd try to intercept activate vs. ForceGreeting , e.g.
begin NPClocalScript; towards top of NPC scriptif ( OnActivate )    set BM_Withme to 1    activate    returnendifif ( BM_Withme )    if ( MenuMode )    else        set BM_Withme to 0    endifendif; ....end



I'm having problems in testing a script - sometimes it works other times it doesn't - I need to set a Global variable to either 1 or 0 - this is used in dialogue filtering

What is supposed to happen is that when the companion is near the Global BM_Withme is set to 1 and when the companion is not in range it gets set back to 0

How I have written it at the moment is

Begin my_script

float nearme

set nearme to ( Player GetDistance "BM_Fleur" )

if ( nearme > 600 )
if ( BM_Withme == 1 )
set BM_Withme to 0
endif
elseif ( nearme <= 600 )
if ( BM_Withme == 0 )
set BM_Withme to 1
endif
endif
end

Any idea what I am doing wrong?
User avatar
Eliza Potter
 
Posts: 3481
Joined: Mon Mar 05, 2007 3:20 am

Post » Fri May 04, 2012 1:48 am

Thanks abot and NMZ - in the end I successfully tested

if ( "BM_Fleur"->GetDistance Player > 512 )
set BM_Withme to 0
elseif ( "BM_Fleur"->GetDistance Player <= 512 )
set BM_Withme to 1
endif

I was starting to get paranoid that reloading a game was somehow stopping the Global script from running - but have not seen any evidence to prove that yet

Thanks to you both for chipping in with thoughts - I know this side of the forum is pretty quiet these days so having such quick replies is much appreciated :)
User avatar
Emzy Baby!
 
Posts: 3416
Joined: Wed Oct 18, 2006 5:02 pm

Post » Fri May 04, 2012 3:09 am

Ah, of course -- should have remembered that about GetDistance. Glad you got it working!
User avatar
Dominic Vaughan
 
Posts: 3531
Joined: Mon May 14, 2007 1:47 pm

Post » Fri May 04, 2012 2:51 am

Just came across an odd problem in Gnisis - every time I try and leave the tradehouse Fleur vanishes - if I go back into the building sometimes she is still there other times missing - this is the first door I've ever had problems in getting her through

I don't have any extra scripts running in that cell I went back and retested that she could walk through doors in Balmora and Ald-Ruhn but as soon as I go back to the Tradehouse and walk in she warps to me correctly then try to go out and she is stuck - has anyone had any issues with that cell and companions before?
User avatar
Mizz.Jayy
 
Posts: 3483
Joined: Sat Mar 03, 2007 5:56 pm

Post » Fri May 04, 2012 8:21 am

I am curious. Are you using double (GetDistance is not fast) condition test as safety measure? IMO rumours about else not working are only rumours due to forcegreeting bug/people forgetting to close nested if structures properly. Anyway, with single if else endif structure it is very easy to test if simpler code works, e. g.
if ( "BM_Fleur"->GetDistance Player > 512 )	set BM_Withme to 0else ; if ( "BM_Fleur"->GetDistance Player <= 512 ) ; unneeded	if ( "BM_Fleur"->GetDistance Player > 512 )  ; test only		messagebox "this will never happen, so better delete me" ; test only	endif ; test only	set BM_Withme to 1endif
[EDIT]typos, clarification
User avatar
Danger Mouse
 
Posts: 3393
Joined: Sat Oct 07, 2006 9:55 am

Next

Return to III - Morrowind