Battle System Tutorial by Flik
How on Earth do you create a battle system in Sphere? Simple, you script it. (Okay, so it can be a bit difficult.)
Contents
Introduction
We're going to break the battle system down into separate bits so that it's easier to create.
Since most RPG battle systems are menu-driven, you may want to learn how to use a menu object. (Creating a menu using flik_menu.js)
We'll be using objects too, if you want to read up on that. (Simple OOP in JavaScript)
You don't need to read those to understand this, though.
Combatants: things that can fight
Okay, the people or things or whatever that are fighting? We'll call them 'combatants'.
We'll have a list of combatants in an array.
var combatants = new Array();
So whenever a combatant appears, they go into that array. A player is the same as a monster, okay? :)
function Combatant(name) {
this.name = name;
this.x = 50;
this.y = 50;
this.min_hp = 0; // don't ask why
this.hp = 10000;
this.max_hp = 50;
this.str = 10;
this.type = "monster";
}
Combatant.prototype.clone = function() {
var obj = new Combatant();
for (var i in this)
obj[i] = this[i];
return obj;
}
Sidetrack: Why clone the object?
Putting our combatants in a battle
So this creates a Combatant object when we do:
var freddy = new Combatant("Freddy"); // create the object
freddy.type = "player"; // set the type to "player"
freddy.x = 200;
var blob = new Combatant("Blob");
blob.hp = 5000;
combatants.push(freddy.clone()); // freddy has joined the party
combatants.push(blob.clone()); // uh oh, we have a monster to fight
Sidetrack: Why the huge hp values?
Figuring out if the battle is over
Now, how do we check to see if we need to fight someone? Well, we loop through the combatants array and check the type of each combatant.
function GetTotalMonsters() {
var total_monsters = 0;
for (var i = 0; i < combatants.length; ++i)
if (combatants[i].type == "monster")
total_monsters += 1;
return total_monsters;
}
function GetTotalPlayers() {
var total_players = 0;
for (var i = 0; i < combatants.length; ++i)
if (combatants[i].type == "player")
total_players += 1;
return total_players;
}
Drawing the combatants
Okay, so let's add some rendering code to the Combatant object.
Combatant.prototype.render = function() {
var font = GetSystemFont();
font.drawText(this.x, this.y, this.name);
font.drawText(this.x, this.y - 20, this.hp);
}
Figuring out turns
We also need some sort of system for finding out who's turn it is. Enter... the turn list:
var turn_list = new Array();
AI
Also, now let's add some AI to them:
function GetAliveMonstersArray() {
var total_alive = new Array();
for (var i = 0; i < combatants.length; ++i)
if (combatants[i].type == "monster" && combatants[i].hp > 0)
total_alive.push(i);
return total_alive;
}
function GetAlivePlayersArray() {
var total_alive = new Array();
for (var i = 0; i < combatants.length; ++i)
if (combatants[i].type == "player" && combatants[i].hp > 0)
total_alive.push(i);
return total_alive;
}
function Attack(from_who, on_who) {
combatants[on_who].hp -= combatants[from_who].str;
}
Combatant.prototype.AI = function() {
if (this.type == "player") {
// create menus here
var attack_selection = GetAliveMonstersArray()[0]; // we attack 1st monster
Attack(turn_list[0], attack_selection);
} else if (this.type == "monster") {
// just normal attacking here
var attack_selection = GetAlivePlayersArray()[0]; // they attack 1st player
Attack(turn_list[0], attack_selection);
}
}
Drawing the battle
Finally, we do:
function RenderBattle() {
for (var i = 0; i < combatants.length; ++i)
combatants[i].render();
}
Bringing it all together
function Battle() {
var run_away = false;
while (GetAlivePlayersArray().length > 0
&& GetAliveMonstersArray().length > 0
&& !run_away) {
if (IsKeyPressed(KEY_R))
run_away = true;
// deal turns
if (turn_list.length == 0) {
for (var i = 0; i < combatants.length; ++i)
turn_list.push(i);
}
// process the current turn
if (turn_list.length > 0) {
combatants[turn_list[0]].AI();
turn_list.shift();
}
RenderBattle();
FlipScreen();
}
}
Press 'R' to run from battle.
Trying it out
Let's say that all of that is in a file called freddyvsblob.js. In your main/startup script:
RequireScript("freddyvsblob.js");
function game() {
SetFrameRate(60);
Battle();
}
If you ever need to do it again, just do this:
combatants.push(freddy.clone());
combatants.push(blob.clone());
Battle();
The whole script
You can find all the battle system code at Flikky's site: http://sphere.sourceforge.net/flik/files/freddyvsblob.js .
By Flikky, updated for the wiki by Tunginobi.