Hello,
recently I had problem with Fliggerty's slave mod here. It was caused by setting in MCP, but in the meantime I discovered some flaws in the original script, that as far as I know uses Grumpy's companion template. I decided I will try to improve it a bit. Right now, I'm applying the fixes to Fliggerty's slave mod, as that's the one I started to work with, but eventually I hope to create updated version of companion template. Unfortunatelly, I'm not very experienced with companion scripting, so any thoughts and code explanations are highly appreciated.
Original slaveScript from Fliggerty's Slave mod
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
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
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
if ( MenuMode == 1 )
if ( GetPCSleep == 0 )
return
endif
endif
if ( weapUse == 1 )
if ( Player->GetWeaponType <= 8 )
setmarksman 0
elseif ( weapUse == 1 )
if ( Player->GetWeaponType >= 9 )
setmarksman 200
endif
endif
endif
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
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 )
if ( GetSoundPlaying "Weapon Swish" == 0 )
set sheatheTimer to 0
set soundPlayed to 1
elseif ( sheatheTimer > 4 )
if ( GetSoundPlaying "crossbowShoot" == 0 )
set sheatheTimer to 0
set soundPlayed to 1
elseif ( sheatheTimer > 4 )
if ( GetSoundPlaying "bowShoot" == 0 )
set sheatheTimer to 0
set soundPlayed to 1
endif
endif
endif
endif
endif
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 ( 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 ( GetCurrentAIPackage == 3 )
if ( GetPCSleep == 1 )
StartScript fs_compLevel
endif
if ( GetPCSneaking == 1 )
ForceSneak
elseif ( GetPCSneaking == 0 )
ClearForceSneak
endif
if ( Player->GetEffect sEffectLevitate == 1 )
if ( flyCheck == 0 )
cast fs_comp2_lev_bog player
addspell fs_comp2_lev
set flyCheck to 1
endif
endif
if ( Player->GetEffect sEffectLevitate == 0 )
if ( flyCheck == 1 )
removespell fs_comp2_lev
set flyCheck to 0
endif
endif
if ( Player->GetEffect sEffectWaterWalking == 1 )
if ( wwCheck == 0 )
cast fs_comp2_ww_bog player
addspell fs_comp2_ww
set wwCheck to 1
endif
endif
if ( Player->GetEffect sEffectWaterWalking == 0 )
if ( wwCheck == 1 )
removespell fs_comp2_ww
set wwCheck to 0
endif
endif
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
if ( GetWeaponDrawn == 1 )
if ( flyCheck == 0 )
set combatCheck to 1
set timer to 0
set warp to 1
return
elseif ( GetWeaponDrawn == 1 )
if ( flyCheck == 1 )
set combatDone to 1
set timer to 0
set warp to 1
return
endif
endif
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 ( GetSquareRoot, t1 )
if ( coDist > 360 )
set doOnce to 0
endif
if ( coDist > 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 ( GetSquareRoot, t3 )
if ( coDist2 > 360 )
set doOnce2 to 0
endif
if ( warp == 0 )
if ( coDist > 350 )
if ( GetDistance Player > 680 )
SetPos x bx
SetPos y by
SetPos z bz
AiFollow Player 0 0 0 0
elseif ( warp == 0 )
if ( coDist2 > 350 )
if ( GetDistance Player > 680 )
SetPos x cx
SetPos y cy
SetPos z cz
AiFollow Player 0 0 0 0
endif
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
Current improved slaveScript:
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
float playerDistance
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 )
;calculate initial player distance
set playerDistance to GetDistance player
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 ( playerDistance > 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 ( playerDistance < 70 )
AIWander 300 0 0 0 0
set c_move to 1
endif
endif
endif
endif
if ( c_move == 1 )
if ( playerDistance > 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 )
;recalculate player distance only every 20 frames and if current AI package is follow (3)
set playerDistance to GetDistance player
if ( playerDistance < 300 )
setSpeed 15
setAthletics 15
elseif ( playerDistance > 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
Current improvements:
- Several blocks of code were shortened and simplified. They are marked as 'SIMPLIFIED'.
- Added new warp compatible with Ultimate Galleon mod.
- Removed calls of 'GetsquareRoot'. Where originally was something like 'GetSquareRoot(x) > y' it is now altered to 'x > y*y'.
- Original script calls 'GetDistance player' about 5 times every frame. Altered so it calls it only once every 20 frames.
Any input is highly appreciated