ID:153331
 
By "tatical battle system" I mean a turn based battle between two teams on a grid(ex: Shining Force, Final Fantasy Tactics, and more recently Gladius[which I would recommend to anyone who's a fan of this battle system]). I only call it a tactical battle system because all the games I've seen with the word "tactics" in the title uses one. Anyway, I was toying around trying to make one(without planning ahead as usual) and while it probably would have worked if I kept at it, it wasn't very desirable.

So I need some ideas on how to go about making this work cleanly. In my first try I just had one big looping proc that was called to start a battle. That seemed like a good way to go until I got to turns. When a players turn starts I want to give \him some commands, and allow them to move around in a designated area without a time limit. I did that in a proc(TakeTurn(), for future reference) and had the main loop wait for a return value, but finding out when the turn was over is what seemed wrong to me. The only way I could think of to do it, was to have TakeTurn() loop every second and check a flag variable that is set when they finished there turn.

That's my main concern about this, but anything related to making this type of battle system should help out. I'm limiting the players movement to a diamond shape instead of a square(thanks to a snippet posted by Shadowdarke a while ago) and it's working as expected. I haven't tried to do anything to adjust the movement range to account for densities yet, so I might as well get some opinions on that as well. Examples:
 Fig.1    Fig.2    Fig.3
o o
ooo ooo o o
ooooo ooDoo ooDoo
ooooooo ooooooo ooooooo
ooooo ooooo ooooo
ooo ooo ooo
o o o

o = Movement range
D = Density
This is with a movement range of 3.


This should explain what I intend to accomplish. I'd like to take any turf that is dense(or has something dense occupying it) out of the movement range.(Fig.2) Then I would like to remove any other turfs they couldn't get to with a certain number of steps(no diagonals).(Fig.3) Should I try to use some math(wich I'm not great at =p), a mix of get_dir() and get_dist(), or something else entirely to achieve this? Thanks for reading, and replying if you see fit. Now, I leave you with another example of the movement range idea. :p

    o          o         
ooo ooo o o
ooooo ooooo ooooo
ooooooo oooDooo oooDooo
ooooooooo ooooooooo ooooooooo
ooooooo ooooooo ooooooo
ooooo ooooo ooooo
ooo ooo ooo
o o o

This is with a movement range of 4.
I made a tactics style range system before. It more or less traced the steps while keeping a list of checked turfs in a list. I'll see if I can dig it up.

[EDIT] Here it is in it's full, uncommented form.


turf
var
cost = 0

proc
queryCost()
return queryElevation()

queryElevation()
return 0
datum
pathobj
var
cost
x
y
proc

cardinal(atom/ref)
return (list(get_step(ref,NORTH),get_step(ref,SOUTH),get_step(ref,EAST),get_step(ref,WEST)))

tactics_dist(atom/ref, atom/targ)
return sqrt( (ref.x-targ.x)**2 + (ref.y-targ.y)**2)

tactics_orange(dist as num, downhill=FALSE, atom/ref = usr)
return tactics_range(dist,downhill,ref)-tactics_range(0,downhill,ref)

isdense(atom/A)
var/retval = 0
retval += A.density
for(var/atom/B in A.contents)
retval += isdense(B)

return retval


tactics_range(dist as num, downhill=FALSE, atom/ref = usr)
var/list/turfs = list(ref.loc)
var/datums[world.maxx][world.maxy]
var/datum/pathobj/refloc = new()
refloc.cost = 0
refloc.x = ref.x
refloc.y = ref.y
datums[ref.x][ref.y] = refloc
for(var/x=1, x<=dist,x++)
for(var/turf/T in turfs)
for(var/turf/t in cardinal(T))
if(isdense(t))
continue
var/cost = 1+t.queryCost()
var/datum/pathobj/p = datums[T.x][T.y]
cost += p.cost
var/elevdiff
var/turf/tref = locate(p.x,p.y,ref.z)
elevdiff = t.queryElevation()-tref.queryElevation()
if(!downhill)
elevdiff = abs(elevdiff)
cost += elevdiff
if(cost <= dist)
var/datum/pathobj/np = new()
np.cost = cost
np.x = t.x
np.y = t.y
if(datums[t.x][t.y])
var/datum/pathobj/test = datums[t.x][t.y]
if(test.cost > cost)
datums[np.x][np.y] = np
turfs.Add(t)
else
datums[np.x][np.y] = np
turfs.Add(t)
return turfs


xrange(dist as num, atom/ref = usr)
var/list/turfs = list(ref.loc)
for(var/x=1,x<= dist, x++)
for(var/turf/T in turfs)
if(tactics_dist(ref,T) < dist)
for(var/turf/T2 in cardinal(T))
if(tactics_dist(ref,T2) <= dist)
turfs.Add(T2)

return turfs


If some of the procs look familiar, they are. The procs cardinal() and xrange() are pulled straight from Abyssdragon.Basicmath, with minor to no modifications. I found it easier to use a couple of procs rather than use the full library as I was planning on releasing this as a library at some point (with full credit mind you). I believe that the formula for tactics_dist() was also pulled from Basic Math.
An easy way to advance turns is to just call the turn advancement proc whenever a player's turn ends.
In response to sapphiremagus
sapphiremagus wrote:
var/list/turfs = list(ref.loc)

I never thought of doing something like that, go fig.
In response to Goku72
Why do you use "Reply with quote" and leave the entire original post in there when your comment pertains to only one line, and even then you resaid the line in your post? I have seen others do that too, and I am just curious why. Is it habbit to reply with quote all the time so you can see it while you are typing the reply, then you just leave it there?
In response to Loduwijk
Meh, I some times hit it on accident and don't even realize it. >.>
I, too am working on a "tactical" battle system, though I haven't quite got around to movement. I have procrastination problems, so the hardest things always seem to come last. I was planning on simply restricting movement to a square, but your efforts have encouraged me to try a little harder. I hope you have fun building your game, YMIHere.
Thanks for the input guys, I put this off for now to work on some Single Tile Mini-games for the contest, but I'll get back to it and upload a demo when I'm finished. =)
In response to MetalMan42
I'm glad I could be of assistance. =)