Turn Based Combat System

Hey! I’m currently starting as a developer with little experience, and I would like to make a turn based combat system like South Park: The Stick of Truth, just with a 4-Member party system, revamped combat, enemy classes, and prompts. I would like to hear all of your scripting ideas and examples!

5 Likes

Each of those have their own challenges but I can give you some pointers.
For combat, I’d recommend you read up on state machines. They’re essential for writing a system that is easy to work with.

The battle system I made used 4 states: BattleStart, BattleTick, BattleExecute and BattleOver. BattleStart would setup the battle (loading the scene in and getting the enemy and party stats), BattleTick would check for player input and get each of the attacks that each party member or enemy would do and BattleExecute would execute those actions in order of speed. BattleOver cleaned up the scene.

For the party system I simply stored each party member in a table with basic stats and what attacks they could use. They also each had some methods for leveling up, and auto mode. If the player put auto mode on, the auto mode method would be called when it was their turn, which allowed them to for example cast a heal spell if any of their party members were low on health, etc. Enemies had very similar structure to party members and attacks were just a function that took in the caster and the victim and handled the data accordingly.

Sorry for the wall of text, but turn based rpgs can get complicated. Feel free to ask any questions.

7 Likes

Turn Based RPGs are some of the hardest games to program, but in addition to what Captain said above, I also would suggest learning to use pathfinding so that your “Party members” find their way to their targets and know where to stand for what animations. It’ll be a super helpful way to control the placement and movement of party members!

If you’re just starting to code before you jump into this I would look up a few starting tutorials and try to understand and replicate the code on your own before jumping into something like this. However after you understand the basics, these concepts should come like no tomorrow! Don’t give up!

The first game I started working on was an MMO about four years ago now, and I always backed down because of how big the idea was. If I hadn’t backed down that MMO would be done, so just remember that because this is a big project, it’ll be done eventually!

I wish you the best of luck

2 Likes

We’ll go over this step by step, so I’ll take some steps for all four of them, how should BattleStart be scripted as? More specifically, being within a certain range of an enemy NPC

1 Like

Thank you! I’ll be active in asking questions and following instructions, I’ll be sure to give you guys credit as special thanks.

1 Like

I’m making a turn-based RPG inspired by Stick of Truth as well! I agree heavily with what CaptainAlbator said, it’s very similar to the system I’ve made and it works well.One thing I did was giving each of my playable characters their own module script that includes all sorts of information. It includes all their abilities, their casting methods (because some abilities are AoE column/row based while others are single target-- and some abilities we want to cast on enemies and some we want to cast on allies), alongside their base HP, damage, and the level modifiers that would tweak their values based on the player’s character level. I also made a separate module script to handle their animations, since some abilities will have very flashy animations and I think setting it up separately from the logic makes it easier to manage.

It can seem difficult at first especially when creating the enemy players, but don’t give up! If you structure your enemies like your player characters it’s really cool to see the system play them like a human would.

I sort of wrote a wall of text without saying much but basically I’m suggesting organization and making a plan in your head before you dive in! I wrote down all my ideas on how to handle mechanics and it paid off in the long run.

Here’s a video of my project! You can see that even the way the characters are laid out is reminiscent of Stick of Truth cuz I really loved that game! (It’s still early and missing a lot of stuff obvi!)
https://streamable.com/5whjc2

3 Likes

How are you gonna recreate the chef boss (fight) or the princess kenny one? Besides good luck on your project it’ll turn out great! As for OP, don’t forget cutscenes they’re essential! They’re pretty easy to recreate too.

2 Likes

That is incredible work! I’m always surprised about how much Roblox developers can do!

1 Like

The story isn’t based off of South Park! I just liked the gameplay of SoT so I based it off of that, however the characters and stuff are based off of my other game! Thank you though!!! I appreciate it^^

2 Likes

Just for more specification, Im using this style of combat system, and branch it out for use in quests, main story, and random encounters. Since I’m planning to make it a single-player game, I feel like making an engaging story within the game, complete with cutscenes, dialogue, and boss NPC’s. So I appreciate all of your guys’ support!

What sort of tutorials would you recommend? Links would be helpful.

Okay, so I found a template for state machines, does this work out? If so, what do I need to edit inside?

That’s for Lua, you can use it in Luau but it would require a rewrite to meet the standards of roblox engine, you can use other libraries for Luau.

1 Like

Alright, I’ll try and see if I can rewrite it, thanks.

Okay, I attempted to make some code, tell me what you all think!

-- Define some variables for the state machine
local currentState = "BattleStart"
local partyMembers = game.Workspace.PartyMembers:GetChildren()
local enemyMembers = game.Workspace.EnemyMembers:GetChildren()
local partyStats = {}
local enemyStats = {}

-- Define some functions for the state machine
local function enterBattleStart()
	-- TODO: Insert code to set up the battle scene and get stats for all party and enemy members
end

local function enterBattleTick()
	-- TODO: Insert code to check for player input and determine the actions to be taken by each party member and enemy
end

local function enterBattleExecute()
	-- TODO: Insert code to execute the actions determined in the BattleTick state, in order of speed
end

local function enterBattleOver()
	-- TODO: Insert code to clean up the battle scene and end the combat sequence
end

local function transitionToState(newState)
	-- TODO: Insert code to transition from the current state to the new state
end

-- TODO: Define more functions as needed for your specific game

local function transitionToBattleTick()
	currentState = "BattleTick"
	enterBattleTick()
end

local function transitionToBattleExecute()
	currentState = "BattleExecute"
	enterBattleExecute()
end

-- Set up the state machine loop
while currentState ~= "BattleOver" do
	if currentState == "BattleStart" then
		enterBattleStart()
		transitionToBattleTick()
	elseif currentState == "BattleTick" then
		enterBattleTick()
		transitionToBattleExecute()
	elseif currentState == "BattleExecute" then
		enterBattleExecute()
		transitionToBattleTick()
	end
end

enterBattleOver()

2 Likes

A state machine is something that is so simple you don’t need to use a library for it.

All you need is a module that stores the different states and has methods to switch the active state. If you want to keep previous states active you can use a stack to store the active states and only update the top one. Here’s an example of a stack-based state machine:

local StateMachine = {}
StateMachine.__index = StateMachine

function StateMachine.new()
    return setmetatable({
        States = {},
        StateStack = {},
    }, StateMachine)
end

-- Get the top state
function StateMachine:Peek()
    return self.StateStack[#self.StateStack]
end

-- Add a state to the states table with the given name
function StateMachine:Add(stateName, state)
    self.States[stateName] = state
end

-- Push a state onto the stack
function StateMachine:Push(stateName, ...)
    table.insert(self.StateStack, self.States[stateName])
    self:Peek():OnEnter(...)
end

-- Pop the state stack
function StateMachine:Pop(...)
    self:Peek():OnExit(...)
    table.remove(self.StateStack, #self.StateStack)
end

return StateMachine

Then, a state might look like this:

local State = {
    connection = nil,
}

function State:OnEnter()
    -- state code
    self.connection = game:GetService("RunService").Heartbeat:Connect(function(dt)
        -- run code every frame
    end)
end

function State:OnExit()
    -- cleanup code
    if self.connection then
        self.connection:Disconnect()
    end
end

return State

Then, to use, you would do:

local StateMachine = require(path.to.statemachine.module)
local BattleState = require(path.to.battlestate)

local stateMachine = StateMachine.new()
stateMachine:Add("Battle", BattleState)

stateMachine:Push("Battle") -- Pushes the battle state on the stack which runs it

This is what I used for my turn based combat system a while back and it worked wonderfully. Note that you will need to modify this to get it to do what you need, this is only an example.

3 Likes

Oh, I didn’t know it would be that simple, thanks! I’ll try it out and let you know later into the day

Alright, so I almost have it set up, but I want something for BattleStart where once you’re within the enemy’s range, then it teleports to another room, which is the battle stage, how can I make that happen?

Have it switch the state when the condition is met.

1 Like

So, for example, of I get into an area within the enemy, then the BattleStart state activates, by telling the script that once the player is within the radius, then it will call to the state, right?