News: Welcome back to Bullworth! If you haven't already, you will need to reset your password..


Author Topic: Lua Tutorial: Non-STimeCycle Freeroam Mods  (Read 330 times)

0 Members and 1 Guest are viewing this topic.

Offline Altamurenza

  • Jr. Member
  • **
  • Posts: 99
  • Gender: Male
  • lack of source, lack of innovation.
    • View Profile
Lua Tutorial: Non-STimeCycle Freeroam Mods
« on: April 06, 2022, 02:34:33 AM »
- 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 5

There 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 (EASY) -

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.lua
Code: [Select]
if 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.lua
Code: [Select]
if 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 (MEDIUM) -

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.lua
Code: [Select]
if 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:
Code: [Select]
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
« Last Edit: April 07, 2022, 03:31:02 PM by Altamurenza »

Offline RanggaBS

  • Jr. Member
  • **
  • Posts: 64
  • Gender: Male
  • I don't know.
    • View Profile
    • This is website title.
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #1 on: April 06, 2022, 08:25:55 PM »
You look like very obsessed with this game, XD. Nice find.

Btw, where's level 3?
Quote
I differentiate it into three levels, ...

Offline Altamurenza

  • Jr. Member
  • **
  • Posts: 99
  • Gender: Male
  • lack of source, lack of innovation.
    • View Profile
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #2 on: April 06, 2022, 10:05:08 PM »
You look like very obsessed with this game, XD. Nice find.

Nope, it's not about obsession actually.
Anyway, thanks.
Btw, where's level 3?
Quote
I differentiate it into three levels, ...

Yeah, the level three (hard) is missing.
It supposed to be specific activation method.

I missed the hard one because i was having a hard time to explain it too :wacko:

Offline SimonBestia

  • Full Member
  • ***
  • Posts: 276
  • Gender: Male
  • Bully-Board's Best Weeb
    • View Profile
    • Youtube Channel
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #3 on: May 06, 2022, 05:15:12 AM »
- LEVEL 0 -
Use Level 1 to only start basic threads with just "LaunchScript(ModScriptInSCRIPTSIMG.lua)" and create a Bully ModLoader that writes as many of those based on the mods users have ticked in its UI.

Heh. One can only dream.  :biggrin:

Offline Altamurenza

  • Jr. Member
  • **
  • Posts: 99
  • Gender: Male
  • lack of source, lack of innovation.
    • View Profile
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #4 on: May 06, 2022, 10:45:39 AM »
How can we create a mod loader with LaunchScript meanwhile the game cannot handle more than 5 launched scripts.

Launched scripts by the game:
1. STimeCycle.lua (you already know it)
2. StoreTransition.lua (triggered by area transition)
3. MGLockPicking.lua (triggered by lockpicking for the first time)

So.. you can only load two more scripts as far as i remember it correctly.
Otherwise, your game will crash immediately.

Offline SimonBestia

  • Full Member
  • ***
  • Posts: 276
  • Gender: Male
  • Bully-Board's Best Weeb
    • View Profile
    • Youtube Channel
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #5 on: May 06, 2022, 11:40:46 AM »
Oh! That's new.
Never tried having so much loaded at once.

Offline Altamurenza

  • Jr. Member
  • **
  • Posts: 99
  • Gender: Male
  • lack of source, lack of innovation.
    • View Profile
Re: Lua Tutorial: Non-STimeCycle Freeroam Mods
« Reply #6 on: May 06, 2022, 12:11:28 PM »
Yeah, i just confirmed that launching more than 5 scripts crashed my game.