- INTRODUCTION -
We're more than a decade in Bully modding scene, but we still relying ourselves on STimeCycle scripts. We managed to crawl out from ArcRace1 to STimeCycle based script, from arcade mods to freeroam mods. Now, the question is: Why are we stopped here?
That's because we're obviously lack of modding complexity, at least in Lua modding. I think we should start to implement a concept that i would like to call '
Mod's Interdependence' where mod developer should cooperate & add compatibility features for other mods too (if possbile). We know that people demand for having multiple mods at once, so the main obstacle that we should tackle is the variety of script's template.
Need a prove on people demand? Well, i have some.
Prove:
1,
2,
3,
4, and
5There are many ways to make freeroam mods that are not based on STimeCycle. I differentiate it into three levels, so i hope this tutorial can reach everyone with the least knowledge barrier possible. Let's begin.
- LEVEL 1 (BEGINNER) -
First of all, the easiest way to make Non-STimeCycle Freeroam Mod is using Garages.lua or SLvesEff.lua scripts. Both scripts have very short length of code and they are called in '
main.lua' once the game has started. But, they are different from STimeCycle because both scripts were '
called' rather than '
launched' like STimeCycle. That means the script should not have '
main function' and it would not run independently, so there will be some potential conflicts if you are not careful with variables.
To solve the '
main function' problem, use
CreateThread function to create our own '
main function'. But, the fundamental aspect that you should give more attention is variable. '
main.lua' is the central of scripts which has many variables in there, so i will strongly advise you to use '
shared' variable instead of global. It's more flexible compared to global and effective to avoid variable conflicts between your mods and '
main.lua', you can also modify it from your other scripts.
Without further ado, here are the templates that you can use to make freeroam mods.
1) Garages.luaif type(F_InitGarages) ~= 'function' then
F_InitGarages = function()
DATLoad('Garages.DAT', 1)
GarageClearAll()
GarageAdd(TRIGGER._Garage_SchoolGrounds, POINTLIST._Garage_SchoolGrounds)
GarageAdd(TRIGGER._Garage_RichArea, POINTLIST._Garage_RichArea)
GarageAdd(TRIGGER._Garage_BusinessArea, POINTLIST._Garage_BusinessArea)
GarageAdd(TRIGGER._Garage_PoorArea, POINTLIST._Garage_PoorArea)
end
end
_G.MOD_NAME = function()
while not SystemIsReady() or AreaIsLoading() do
Wait(0)
end
while true do
Wait(0)
end
end
shared.gModName_MainThread = CreateThread('MOD_NAME')
2) SLvesEff.luaif not SystemIsReady() then
EffectAddLeavesInArea(POINTLIST._LEAVESMAIN, 0)
EffectAddLeavesInArea(POINTLIST._LEAVESBUSINESS, 0)
EffectAddLeavesInArea(POINTLIST._LEAVESRICHAREA, 0)
end
_G.MOD_NAME = function()
while not SystemIsReady() or AreaIsLoading() do
Wait(0)
end
while true do
Wait(0)
end
end
shared.gModName_MainThread = CreateThread('MOD_NAME')
You can also theoretically implement this activation method in SWinEff.lua, SRoomEff.lua, SLightEff.lua, and Bike_gen.lua. These scripts are just a bit larger compared to Garages.lua and SLvesEff.lua, but it is not a big deal since they already got fully decompiled before.
- LEVEL 2 (INTERMEDIATE) -
Warning: If you have not completely understand the level 1, please master it first!
In level two, we are going to use globally imported scripts such as SInitGl.lua, SGlFunc.lua, SMStat.lua, SScriptTracks.lua, SFaction.lua, SCutscenes.lua, and SMissPass.lua. These scripts do not possess the same activation method as level one, we do our mod activation through
function hooking. The requirement of function we need is pretty much simple, it must be used once the game has started.
These are my most preferred functions to activate our mod through '
function hooking':
-
HasStoryModeBeenSelected()
-
ClothingBuildPlayer()
-
PlayerCreateXYZ(X, Y, Z)
NOTE: There are many references from other scripts too, but 'main.lua' is the most likely place where functions are called upon start. You can start there if you are looking for function to hook.Before we start, there is one big problem that you should expect from the beginning. We only have one fully decompiled script of seven globally imported scripts, and that was SMStat.lua. The other scripts are not suitable for direct edit due to some missing parts, so we will need some extra steps in order to use them as our templates. I will use SInitGl.lua to demonstrate that matter, but i will show you the SMStat.lua first before that.
1) SMStat.luaif type(F_VendettaGreasers) ~= 'function' then
F_VendettaGreasers = function()
return g_3RM01_GreaserLevel > 3 and 0 or 1
end
F_VendettaPreppies = function()
return g_3RM01_PreppyLevel > 3 and 0 or 1
end
end
_G.HSMBS = _G.HasStoryModeBeenSelected
_G.HasStoryModeBeenSelected = function()
-- Make sure our script isn't active yet, it's important step to avoid multiple activation!
if not shared.gModName_MainThread then
_G.MOD_NAME = function()
while true do
Wait(0)
end
end
shared.gModName_MainThread = CreateThread('MOD_NAME')
end
-- Execute function.
return _G.HSMBS()
end
2) THE REST OF THEM (Demonstrated with SInitGl.lua)In this matter, we need the original compiled script in order to be the same as original source code. Why we need the compiled one? That is because we are not sure about things going on there, the source codes are missing some parts due to limitation of the tool. There is a high risk when we use that half-finished source code, it leads us to instability or crash.
Script template:
ImportScript("SInitGl_data.lua") -- It depends on script you want to replace and its name, in this demonstration i want to replace SInitGl.lur.
_G.CBP = _G.ClothingBuildPlayer
_G.ClothingBuildPlayer = function()
-- Make sure our script isn't active yet, it's important step to avoid multiple activation!
if not shared.gModName_MainThread then
_G.MOD_NAME = function()
while true do
Wait(0)
end
end
shared.gModName_MainThread = CreateThread('MOD_NAME')
end
-- Execute function.
return _G.CBP()
end
Now, we need to compiled script (SInitGl.lur) and rename it according to our script (SInitGl_data.lur).
Here's the tutorial:
- Open Scripts.img with IMG Tool 2.0
- Find the name of compiled script we need (SInitGl.lur) and enter
* NOTE: I use SInitGl.lua in this demonstration, so i should find SInitGl.lur- Right click on SInitGl.lur and extract to a folder where your SInitGl.lua is there
- Close IMG Tool 2.0
- Open folder where you extracted SInitGl.lur
- Rename SInitGl.lur to SInitGl_data.lur
* NOTE: You can rename it to anything you want, but i highly recommend a name that close to its original name.- CLOSING STATEMENT -
This is my second tutorial in Bully-Board, i hope i'll be able to share some more experiences soon.
Make sure you read all the explanations carefully to avoid any confusion.
Check out my other tutorials:
-
Lua Tutorial: Exceeding 112KB Script Limit-
Lua Tutorial: Check If a File Exists in Directory