MSFD A guide to making ridable objects
(By MadMax_001)
MadMax shares his insights on how to make ridable objects (e.g. boats) here, especially which problems will arise and what he did to solve them. There is a lot of interesting info here that goes beyond just this specific application, though. You can look at his scripts in the "Fishing Academy" and the "Magic Carpet" Mods (but don't use them in your mod without his consent).
Selecting objects
Practically all objects (statics/activators) can be used. However, selecting the right type of objects is paramount. It will make your scripting a lot easier later on. Now, what type of objects are suitable? Preference is given to small and minimum height ( thickness ). The other important factor is the center point which is also the point where your character will be standing on. This will also save you a lot of programming work later on. If the object center point is not what you want, you can fix this by importing the object to 3DS and move the axis to the point to where you plan your character to stand. I am not going to explain in details how to do it in 3DS, there should be quite a number of tutorials out there which teach you how to do it.
Creating/Deleting objects
I am sure a lot of modders know that you can only move an object through the exterior cells within certain distances. This is because the game will only update and process objects/codes within a certain
distance. When your character gets out of that parameter, the object will actually be frozen or to the player, the object has warped/disappeared into thin air. But, if you trace back to the original cell, the object will re-appear.
Now, to move objects throughout the entire exterior cells, the trick to use here is to create a new object. Everytime when you move to a new cell, the function "CellChanged" will become TRUE for one frame. This is the best time to replace the existing object with a new one. There is one BIG problem that I discovered here. NEVER create an object from an object script. It doesn't seems to work. So, what you need to do is to use a global script to create one instead. At the same time, do not forget to Delete the old object or you will have all these objects spreading in different cells which will cause you major problems later on. Always maintain one object at one time. Below is a simple example you can use:
;----------------
; Object script
;----------------
if ( player->CellChanged == 1 )
Startscript, "Create_obj_script" ; this is the global script
set obj_count to ( obj_count - 1 ) ; global parameter to count how many object exist
Disable
SetDelete, 1
endif
;----------------
; Global script
;----------------
PlaceAtPC "objectname", 1, 0, 0 ; or you can use PlaceItem
set obj_count to ( obj_count + 1 )
Stopscript "create_obj_script"
Ideally, the above script should work like a charm but in reality it is going to cause you major problems. Deleting an object immediately after changing cell may sometimes cause CTD. This is especially true when you have a heavy area loading. To fix this problem, delay the deletion. Introduce a time delay ( I personally find the 1.5seconds to be OK so far ). Here's how the object script will looks like now.
if ( player->CellChanged == 1 )
Startscript, "Create_obj_script" ; this is the global script
Disable
set timer_flag to 1
endif
if ( timer_flag == 1 )
set timer to ( timer + GetSecondsPassed )
if ( timer > 1.5 )
set obj_count to ( obj_count - 1 )
SetDelete, 1
else
return ; stop all other code processing
endif
endif
That is not all. If you plan to move your object at very high speed. There is a possibility that the object may encounter another cell change during the 1.5 seconds delay. You must make sure that the object gets deleted before it gets out of the processing parameter or it will come back and haunt you later. Now the script looks like this.
if ( player->CellChanged == 1 )
if ( timer_flag == 1 )
SetDelete, 1
return
endif
Startscript, "Create_obj_script"
Disable
set timer_flag to 1
endif
if ( timer_flag == 1 )
set timer to ( timer + GetSecondsPassed )
if ( timer > 1.5 )
SetDelete, 1
else
return
endif
endif