ID:272955
 
I'm looking for a good place to start on a "Tactical" rpg turn-based system. I guess the closest thing I can compare it to is Final Fantasy Tactics.

In essence, combat works like this:

1: Combat is "entered", speed or an equivalent stat is tallied between all units participating to determine what order the units take.

2: Combat starts, and the first unit has a chance to act. If it's the player's unit, he is presented with a list of "static" options. Usually, Attack and Move are in this list. Units can generally move and attack/use an item/cast a spell on their turn. Depending on the system, units have a "Speed" attribute that determines how many tiles they can move on their turn.

3: Combat continues... Units that have attacks select "Attack" and if it happens to have a sword, for example, then he may strike any unit in a cross shaped pattern. Ex:

N = Can't attack, diagonal
+ = Player
- = Viable strike areas

N-N
-+-
N-N

Ranged attacks are done within a certain number of tiles around the unit (radius :P).


Can anyone here point me in the right direction? I've seen a handful of "Turn" systems in the demos/libs section, but I don't believe they cover this whole multiple-units-taking-different-turns-with-only-some-of-them -being-controllable thing.

Accepting any and all help!
I forget exactly why I wrote this, but this is a system specifically for roguelikes, for organizing turn orders with arbitrary-length "turns".

//list containing times for actions to be taken
var/list/actionSchedule = list()
//list containing mobs that will take actions
var/list/actors = list()
/* actionSchedule and actors are to be maintained in parallel, with actionSchedule[n]
being the time that actors[n] will take an action */


//the world's "time", in arbitrary units, advanced when actions are taken
var/worldtime = 0

proc
//schedules an action for M in time units of time
scheduleAction(var/mob/M, var/time)
//we're scheduling it for time units of time LATER, so add it to the current time
time = worldtime+time
var/index = 1
var/length = length(actionSchedule)
while(index < length && time >= actionSchedule[index])
//Here, we're going through actionSchedule to find a spot where we can insert the action, in order
// >= instead of > is used so that actions scheduled first are executed first
index++
actionSchedule.Insert(index, time)
actors.Insert(index, M)

//Let mobs take actions until it becomes the player's turn, then stop
advanceTheClock()
//if there are no actions scheduled, then return
if(length(actionSchedule) == 0)
return
var/mob/M
do
//set the time to when the first mob is taking its action
worldtime = actionSchedule[1]
//grab the lucky mob
M = actors[1]
//and remove it and its action from the list
actionSchedule.Cut(1,2)
actors.Cut(1,2)
while(!M.takeTurn() && length(actionSchedule) > 0)
/* the loop continues until we run out of actions (this is bad, means there's NOTHING left)
or the mob that took its turn is a player, which causes takeTurn() to return 1 */



mob
proc
takeTurn()
//The children of this procedure would contain the AI routines for a mob to take their turn
//after taking their action, a new one should be scheduled with scheduleAction()
return 0 //return 0 when not a player
player
takeTurn()
//For the player, we would put something that would unlock their ability to take actions
//because the player should only be able to make a move when it's their turn.
//The player's action should call advanceTheClock() again, in addition to scheduleAction()
return 1 //return 1 when a player


This would all likely go within a datum which would represent each fight, rather than global.

The start of a fight would be populating the actors and actionSchedule lists, by calling scheduleAction(M, 0) for each mob, in order of when you want them to take turns. Then, call advanceTheClock() to start the turn cycle.

The takeTurn() proc handles all turn-taking. For AI, it should immediately do what's needed (sleeping would be acceptable), call scheduleAction() to prepare its next action time, and then return 0. For a player, it should enable the player's actions and then return 1. Once the player takes an action, call scheduleAction() to schedule the next action, then advanceTheClock() to start the turn loop again.

It should be rather unobtrusive, so anything else you need to do should be independent of what's needed. For example, to get a circle range value, you can do this:

proc/circle(var/center, var/radius)
var/r2 = radius*radius
var/list/L = list(center)
for(var/turf/T in orange(center, radius))
var/dx = center.x - T.x
var/dy = center.y - T.y
if(dx*dx + dy*dy <= r2)
L += T
return L


Range=1 would return a cross, like you want. Larger values would return more circle-ish circles (for any whole numbers, by the way, there will be "points" in the cardinal directions, but you can use decimals to smooth those). It's not the fastest algorithm, but theoretically you're not going to be calling it too often, so that's okay.
In response to Garthor
hey im kinda new here and can you break it down into like an easy-to-understand version plz so i can use it in my games? Im pretty sure this is exactly waht i want
I've seen a handful of "Turn" systems in the demos/libs section, but I don't believe they cover this whole multiple-units-taking-different-turns-with-only-some-of-them -being-controlla ble thing.
To be clear, my Turns and Phase libraries allow anything. They're just frameworks for handling turns. Who controls what is up to the developer.