Thank you for your feedback, Erg!
I went ahead and did more tweaks to the script.
I simplified two or three if blocks that seemed to be overly complicated and substitued them with equivalent but better ones (marked with word SIMPLIFIED, for original refer to my previous post). I removed calculation of GetSquareRoot and instead used values powered by 2, as the command is pretty slow AFAIK. I also changed the warp check for coDistance to 350 instead of 300, as most other companions out there seem to use 350. I would have a question and that is whether I need to change the value also somewhere else besides the warp block?
Also the script uses GetPlayerDistance several times, so I think it would be better to compute it once and then use this value. Question is where to compute it. It seems that the value is used only in follow mode, so best place seems to be in the first block that checks if Current AI package is 3. Opinions?
Also I remember there was something about 34th variable not working. Was this meant as any 34th variable in script, or was it 34th short variable, 34th float variable, etc.? Since this script uses more than 34 variables.
Here is the script again:
Spoiler
begin slaveScript
;Slave Status... each slave has a status as follows
;0 = Owned ( default state... does not indicate who they are owned by )
;1 = For Sale ( someone in the game can "sell" this slave via dialogue )
;2 = Owned By the Player ( the player has purchased this slave and the slave follows the player )
;3 = Freed ( the player has freed this slave, the slave eventually disables himself)
;4 = Freed but loyal to Player
;dead = not in slave status, but a state one should check for
short slaveStatus
short NoLore
short loyalty
short OnPCHitMe
float ax
float ay
float bx
float by
float bz
float cx
float cy
float cz
float t1
float t2
float t3
float t4
float coDist
float coDist2
float playz
float timer
float sheatheTimer
float moveTimer
float h_check
short doOnce
short doOnce2
short combatDone
short weapUse
short combatCheck
short soundPlayed
short flyCheck
short wwCheck
short oneTimeMove
short compMove
short c_move
short warp
short c_marksman
short c_speed
short c_athletics
short companion
short nohello
short counter
short addOnce
short p_Check
;doOnce stuff
if ( addOnce == 0 )
AddTopic "-- slave care"
AddTopic "-- slave combat"
AddTopic "-- slave follow"
AddTopic "-- slave commands"
StartScript fs_compLevel
set companion to 1
set addOnce to 1
endif
;slave status stuff
if ( slaveStatus == 0 )
if ( OnPCHitMe == 1 )
StartCombat player
ModPCCrimeLevel 500
set OnPCHitMe to 0
endif
set companion to 0
return
endif
if ( slaveStatus == 1 )
if ( OnPCHitMe == 1 )
StartCombat player
ModPCCrimeLevel 500
set OnPCHitMe to 0
endif
set companion to 0
return
endif
if ( slaveStatus == 2 )
set companion to 1
endif
if ( slaveStatus == 3 )
if ( GetCurrentAIPackage == 3 )
AIWander 512 0 0 0 0 0 0 0 0 0 0 0
endif
if ( GetItemCount Slave_Bracer_Left > 0 )
Drop Slave_Bracer_Left 1
endif
if ( GetItemCount Slave_Bracer_Right > 0 )
Drop Slave_Bracer_Right 1
endif
if ( CellChanged == 1 )
Disable
endif
set companion to 0
Return
endif
if ( slaveStatus == 4 )
set companion to 1
if ( GetItemCount Slave_Bracer_Left > 0 )
Drop Slave_Bracer_Left 1
endif
if ( GetItemCount Slave_Bracer_Right > 0 )
Drop Slave_Bracer_Right 1
endif
endif
;companion script
;if we are in menu and player does not sleep, return
if ( MenuMode == 1 )
if ( GetPCSleep == 0 )
return
endif
endif
;block for fight settings "use weapon I use"
;sets marksman to 0 if player uses Melee weapon
;sets marksman to 200 if player uses Ranged weapon
;SIMPLIFIED
if ( weapUse == 1 )
if ( Player->GetWeaponType <= 8 )
setmarksman 0
elseif ( Player->GetWeaponType >= 9 )
setmarksman 200
endif
endif
;player hit this slave
;if disposition is too low, slave revolts
;otherwise lower disposition
if ( OnPCHitMe == 1 )
if ( GetDisposition < 10 )
if ( GetFight < 80 )
MessageBox "That's the last straw!"
SetFight 100
set OnPCHitMe to 0
AIWander 0 0 0 0
endif
else
if ( loyalty > 0 )
set loyalty to ( loyalty -1 )
endif
ModDisposition -5
set OnPCHitMe to 0
endif
endif
;combat check - some kind of test whether combat is over?
if ( combatCheck == 1 )
set sheathetimer to sheatheTimer + GetSecondsPassed
if ( GetSoundPlaying, "Weapon Swish" == 1 )
set sheatheTimer to 0
return
elseif ( GetSoundPlaying, "crossbowShoot" == 1 )
set sheatheTimer to 0
return
elseif ( GetSoundPlaying, "bowShoot" == 1 )
set sheatheTimer to 0
return
elseif ( sheatheTimer > 4 )
set sheatheTimer to 0
set soundPlayed to 1
endif
endif
;again something with combat, no idea what exactly is it good for
if ( soundPlayed == 1 )
equip "silver dagger"
removeitem "silver dagger" 1
; messagebox "Working"
set soundPlayed to 0
set combatCheck to 0
set combatDone to 1
endif
;if combat is over, toggle warping
if ( combatDone == 1 )
set timer to timer + GetSecondsPassed
if ( timer > 6 )
set timer to 0
set combatDone to 0
set warp to 0
endif
endif
;if slave is in follow mode
if ( GetCurrentAIPackage == 3 )
;if player sleeps, adjust slave skill values
if ( GetPCSleep == 1 )
StartScript fs_compLevel
endif
;force sneak if player is sneaking
if ( GetPCSneaking == 1 )
ForceSneak
elseif ( GetPCSneaking == 0 )
ClearForceSneak
endif
;if player levitates, also levitate
if ( Player->GetEffect sEffectLevitate == 1 )
if ( flyCheck == 0 )
cast fs_comp2_lev_bog player
addspell fs_comp2_lev
set flyCheck to 1
endif
endif
;levitation stop
if ( Player->GetEffect sEffectLevitate == 0 )
if ( flyCheck == 1 )
removespell fs_comp2_lev
set flyCheck to 0
endif
endif
;if player water walks, also water walk
if ( Player->GetEffect sEffectWaterWalking == 1 )
if ( wwCheck == 0 )
cast fs_comp2_ww_bog player
addspell fs_comp2_ww
set wwCheck to 1
endif
endif
;water walk stop
if ( Player->GetEffect sEffectWaterWalking == 0 )
if ( wwCheck == 1 )
removespell fs_comp2_ww
set wwCheck to 0
endif
endif
;SIMPLIFIED, adjusts z position according to player in levitate mode
if ( flyCheck == 1 )
if ( GetWeaponDrawn == 0 )
set playz to ( Player->GetPos z )
SetPos z playz
endif
endif
;SIMPLIFIED, fight start
if ( GetWeaponDrawn == 1 )
set combatCheck to 1
set timer to 0
set warp to 1
return
endif
set ax to ( Player->GetPos x )
set ay to ( Player->GetPos y )
if ( doOnce == 0 )
set bx to ( Player->GetPos x )
set by to ( Player->GetPos y )
set bz to ( Player->GetPos z )
set doOnce to 1
endif
set 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 t1
if ( coDist > 129600 ) ;360*360 to avoid using GetSquareRoot
set doOnce to 0
endif
if ( coDist > 32400 ) ;180*180
if ( doOnce2 == 0 )
set cx to ( Player->GetPos x )
set cy to ( Player->GetPos y )
set cz to ( Player->GetPos z )
set doOnce2 to 1
endif
endif
set 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 t3
if ( coDist2 > 129600 ) ;360*360
set doOnce2 to 0
endif
; New warp, compatible with the Ultimate Galleon door
if ( warp == 0 )
if ( GetDistance player > 680 )
if ( coDist > 122500 ) ;350*350
if ( coDist < 462400 ) ;680*680,this prevents the "warping back" effect
SetPos X, bx
SetPos Y, by
SetPos Z, bz
AiFollow player 0 0 0 0
endif
elseif ( coDist2 > 122500 ) ;350*350
if ( coDist2 < 462400 ) ;680*680,this prevents the "warping back" effect
SetPos X, cx
SetPos Y, cy
SetPos Z, cz
AiFollow player 0 0 0 0
endif
endif
endif
endif
endif
;IF ADDITIONS ARE DESIRED, PLEASE ADD THEM BELOW HERE...
if ( GetCurrentAIPackage == 3 )
if ( compMove == 1 )
if ( c_move == 0 )
if ( GetDistance Player < 70 )
AIWander 300 0 0 0 0
set c_move to 1
endif
endif
endif
endif
if ( c_move == 1 )
if ( GetDistance Player > 100 )
AIFollow Player 0 0 0 0
set c_move to 0
endif
endif
if ( oneTimeMove == 1 )
set moveTimer to moveTimer + GetSecondsPassed
if ( moveTimer > 4 )
set moveTimer to 0
AiFollow Player 0 0 0 0
set oneTimeMove to 0
endif
endif
;AND ABOVE HERE.
;ADDITIONS CAN ALSO BE ADDED TO THIS FOLLOWING SECTION, BUT BEWARE OF THE COUNTER.
;Counter can pooch some functions if they need to be checked every frame.
if ( counter < 20 )
set counter to counter + 1
return
endif
set counter to 0
if ( GetCurrentAIPackage == 3 )
if ( GetDistance Player < 300 )
setSpeed 15
setAthletics 15
elseif ( GetDistance Player > 300 )
set c_speed to ( ( Player->GetSpeed ) * 2.25 )
set c_athletics to ( ( Player->GetAthletics ) * 2.25 )
setSpeed c_speed
setAthletics c_athletics
endif
if ( GetItemCount p_restore_health_b >= 1 )
set p_Check to 1
elseif ( GetItemCount p_restore_health_c >= 1 )
set p_Check to 1
elseif ( GetItemCount p_restore_health_e >= 1 )
set p_Check to 1
elseif ( GetItemCount p_restore_health_q >= 1 )
set p_Check to 1
elseif ( GetItemCount p_restore_health_s >= 1 )
set p_Check to 1
else
set p_Check to 0
endif
endif
if ( GetCurrentAIPackage != 3 )
setspeed 40
endif
;ADD ADDITIONAL TOPICS IN THIS SECTION IF REQUIRED.
end slaveScript
EDIT:
Note that I simplified this
if ( flyCheck == 1 )
if ( GetWeaponDrawn == 0 )
set playz to ( Player->GetPos z )
SetPos z playz
elseif ( flyCheck == 1 )
if ( GetCurrentAIPackage != 3 )
if ( GetWeaponDrawn == 0 )
set playz to ( GetPos z )
SetPos z playz
endif
endif
endif
endif
into this
if ( flyCheck == 1 )
if ( GetWeaponDrawn == 0 )
set playz to ( Player->GetPos z )
SetPos z playz
endif
endif
My simplified version does not do the assignment to playz variable. The second command is not important, since it just assigns slave z position it just detected. But in original script, this part of code was actually never executed, since the order of conditions to actually reach this part of code would be:
GetWeaponDrawn != 0 AND flyCheck == 1 AND GetCurrentAIPackage != 3 AND GetWeaponDrawn == 0, which of course is never true.