Turn Based System Framework (Library)

by Albro1
A turn-based system manager. Add-ons contribute to the framework aspect.
ID:865333
 
This is my Turn-Based System "Framework" - or rather, the "Manager". The Turn-Based genre is very broad and tough to narrow down. You could go for a system like Pokemon, Final Fantasy, or many others. I didn't want to pin down on one single one, so I built this, which will ideally help newer developers develop turn-based games.

Now, onto the best part. The thing that makes this a Framework is add-ons. I have one made that demonstrates how to make a simple Pokemon-esque system with this manager.

I will be working on new add-ons, but I wholeheartedly encourage any who want to to make their own add-ons and submit them to me (either via the hub forums or my email, cka12895[at]gmail.com)!

I also encourage feedback on this manager. Do you have ideas on what else could be added to the manager to help make turn-based games that wouldn't be too system-specific? Please suggest it!
Hmm, I'll take a look, but is it as clean and defined as Forum_account's? With his, expectations on libraries are pretty high now.
Finally thanks alot I been wondering how to do a Turn Based system I can learn alot from this.
Because I'm mean, and like embarrassing my fellow moderators in public, I'll mention that Alathon should be checking this baby out soon, and giving you some feedback on it. We always like new libraries, and frameworks also.
In response to Branks
I'd like to think it is. Lol.
Some notes =)

1. I can't tell who is who in combat. I don't know which mobs are mine and who they're attacking. Some graphical effects would be nice (ex: an arrow pointing to whose turn it is, a visual effect for the attack, selecting the target by placing a cursor on the map pointing to the target mob, etc.)

2. It seems like there's still a lot of code in the Pokemon example that shouldn't need to be there. battle.dm, for example - I'm not sure why that stuff isn't handled by the main library.

3. The battle HUD is pretty complicated. The main library could handle a lot of the interface stuff so you could create a menu like this:

mob
my_turn()

// use the main library's menu() proc to create an on-screen menu
// that prompts the user to choose one of these actions.
var/action = menu("FIGHT", "RUN")

if(action == "FIGHT")
// the main library provides the skill_menu() proc which takes
// a list of /skill objects and prompts the user to select one
var/skill/s = skill_menu(skills)

// try to use the ability
s.use(src)

else if(action == "RUN")
run()

skill
proc
use(mob/user)

var/mob/target

// if the user has a client we use the library's target_menu() proc
// to prompt them to select a target from their list of opponents.
if(user.client)
target = target_menu(user.opponents)

// otherwise the AI randomly selects a target
else
target = pick(user.opponents)

effect(user, target)

effect(user, target)
target.take_damage(10, user)

By providing some generic on-screen menus people can develop their own battle menus without having to write any HUD code. You could easily change this code example to include a "MAGIC" command that asks the user to select a magic spell and have the "FIGHT" command be a plain attack.

4. Your code assumes that abilities will target a single opponent. As the example also shows, this should be part of the skill. Some skills might target many enemies or a single ally.

5. Use procs for everything. Don't subtract from the mob's health var, call the lose_health() proc. This lets you able to extend the behavior by overriding a proc:

mob
proc
lose_health(h)
set_health(health - h)

set_health(h)
health = h

// in your code
mob
set_health()
..()
update_health_meter()

If you define a custom health meter you can override the mob's set_health() proc to cause your health meter to update. Another place to use procs is for dealing damage. You want to have a single place where damage is inflicted so there's a single place where you're displaying the event (ex: showing damage numbers or printing a message to the console) and one place where you're applying the combat rules (ex: modifying damage values based on the target's armor).

6. I'm not sure why the test_region_tile is necessary. For demos, keep things simple. Make the creatures defined in a type of /area.

7. There's nothing wrong with having the main library handle a lot of stuff. If you provide procs that people can override or options to disable features, there's no problem.

8. It looks like you're main library forces the order of turns. All players on one side go, then all players on the other side go. This is one of the big ways that games like this vary. Most games have some ordering of the turns based on stats (ex: fastest mob goes first). Some are more complicated than that (ex: Final Fantasy X). some games ask you to input commands for all players, then all actions are performed. Some games have you select an action only when it's that mob's turn to go and the command is performed immediately.

9. I don't like the did_action() proc. If you forget to include that in an ability, the turn will never end. It seems like this is something the main library should handle for you. For example, it calls the mob's my_turn() proc and when that proc returns, the turn is automatically over.
In response to Forum_account
Forum_account wrote:
1. I can't tell who is who in combat. I don't know which mobs are mine and who they're attacking. Some graphical effects would be nice (ex: an arrow pointing to whose turn it is, a visual effect for the attack, selecting the target by placing a cursor on the map pointing to the target mob, etc.)
Thanks for the suggestion.

2. It seems like there's still a lot of code in the Pokemon example that shouldn't need to be there. battle.dm, for example - I'm not sure why that stuff isn't handled by the main library.
Most of it (Including the end() proc) is handled by the library - I just had to override it in that instance to delete everyone in those lists before battle_control.end_battle() was called.

3. The battle HUD is pretty complicated. The main library could handle a lot of the interface stuff so you could create a menu like this:
Thanks, I was wondering about how I could give HUD support without forcing them to set it up a certain way.

4. Your code assumes that abilities will target a single opponent. As the example also shows, this should be part of the skill. Some skills might target many enemies or a single ally.
Thanks for pointing this out, I didn't even think about it. Woops.

5. Use procs for everything. Don't subtract from the mob's health var, call the lose_health() proc. This lets you able to extend the behavior by overriding a proc:
Thanks.

6. I'm not sure why the test_region_tile is necessary. For demos, keep things simple. Make the creatures defined in a type of /area.
I did that because I didn't want to have to lay /areas down everywhere. I used breadth-first searching to do the same effect with one tile. If someone wants to know the details, they can check the link I used in the comments. Otherwise, there isn't much they need to know except to call search(src) override find() if they need to.

7. There's nothing wrong with having the main library handle a lot of stuff. If you provide procs that people can override or options to disable features, there's no problem.
I understand this, I was just a little stumped on what exactly to let the library handle and what was too specific.

8. It looks like you're main library forces the order of turns. All players on one side go, then all players on the other side go. This is one of the big ways that games like this vary. Most games have some ordering of the turns based on stats (ex: fastest mob goes first). Some are more complicated than that (ex: Final Fantasy X). some games ask you to input commands for all players, then all actions are performed. Some games have you select an action only when it's that mob's turn to go and the command is performed immediately.
How would you propose I incorporate these options? A #define flag?

9. I don't like the did_action() proc. If you forget to include that in an ability, the turn will never end. It seems like this is something the main library should handle for you. For example, it calls the mob's my_turn() proc and when that proc returns, the turn is automatically over.

Okey-dokey.
In response to Forum_account
I think the main issue I'm having with HUD support is supporting different amounts of options to choose from. In the Pokemon Add-on, I have 4 choices set up - but what if they want 6? Or 8? That's what I'm having trouble with.
Albro1 wrote:
I understand this, I was just a little stumped on what exactly to let the library handle and what was too specific.

It's very hard to tell. The easiest way is to just make something and see if it makes the game too complex. If you implement things well it should be easy to move stuff from the game to the framework if you realize it'd make more sense there.

How would you propose I incorporate these options? A #define flag?

You shouldn't need these at compile time so they can just be vars on the /turn_control or /battle objects. Something like this:

// in the framework:
battle
var
const
ALL_INPUT_FIRST = 1
ACT_IMMEDIATELY = 2

input_mode = ACT_IMMEDIATELY

// if you want to change it in your game:
battle
input_mode = ALL_INPUT_FIRST

For determining the order mobs go in, I'd just give the turn_control object a proc that is called to determine who goes next. It's default behavior could be cycle through the mobs in order, but people could override it to have it work however they'd like.

I did that because I didn't want to have to lay /areas down everywhere. I used breadth-first searching to do the same effect with one tile. If someone wants to know the details, they can check the link I used in the comments. Otherwise, there isn't much they need to know except to call search(src) override find() if they need to.

People who use this won't expect to have to do that. People understand how to place areas in the map editor. Using a search like that makes it hard to limit where mobs appear and it shows no graphical indication in the map editor. You can define a /area/monsters type that shows an icon in the map editor but disappears at runtime. Doing a BFS on a large map also slows things down and copying the creatures list to every turf will use up extra memory.
In response to Albro1
Albro1 wrote:
I think the main issue I'm having with HUD support is supporting different amounts of options to choose from. In the Pokemon Add-on, I have 4 choices set up - but what if they want 6? Or 8? That's what I'm having trouble with.

You can have the window be sized to fit the number of options. You could also have it scroll but I think that'd be less obvious. The number of slots could also be determined by a variable that developers can customize:

// in the library:
OnScreenMenu
var
slots = 4

New()
// create the slots

// in the project that uses the library:
OnScreenMenu
slots = 6
Well, this is strange. I must be doing something wrong. Why won't the box show up? All of the debugging works.

hud
parent_type = /HudGroup

var
list/menus = list()

HudObject/cursor

proc
new_menu(mob/m, list/choices, icon_state, px, py, width, height)
var/menu/h = new(m)
menus.Add(h)
h.pos(px, py)
for(var/x = px/32 to width)
for(var/y = py/32 to height)
m << "[x]([x * 32]), [y]([y * 32])"
h.add(x * 32, y * 32, icon_state)
h.show()

select()

menu
parent_type = /HudGroup
var
mob/owner

New(mob/m)
..()
owner = m

show()
..()
mob
var
hud/hud
Login()
..()
hud = new(src)
menu(list("test", "test2"))

proc
menu(list/choices, icon_state = "hud", mob/m = src, px = 32, py = 0, width = 8, height = 3)
hud.new_menu(m, choices, icon_state, px, py, width, height)
It might be a problem with having nested HudGroups - I'm not sure that they are 100% working. Try adding the objects to the parent group instead and see if they show up. I also don't see you specify an icon anywhere, but I'm guessing that's just being done elsewhere.
I figured it out - I have to set the HudGroup's icon and layer independently. You may want to update the HudGroup library to give it a layer that will show up automatically? Lol.
Just checked this out, and it looks pretty good. There is plenty of room for it to improve, sure, but its great to see something like this available now. Now, on to the detailed feedback!

1: There is no control scheme notification or guide in the pokemon demo. I don't know about others, but the first thing I do when downloading something like this is run the demo(s), and I believe less experienced developers do the same; so this is a minor concern since it leaves people guessing until they get it.

2 Whenever you run, it simply says your turn ended, rather than giving a proper message about running away. This is minor, and only exists in the Pokemon demo, but running is likely going to be in most projects that use this so I would personally recommend adding some support for the message in this library.

3 A nice addition might be an optional transition into the battle screen. Perhaps a fade to black, a couple flashes of a color, or a graphical effect; just something simple to urge you into battle/the menu. This is likely simple for the developers to add, but this is another common feature across multiple turn-based game types so I thought it might be worth mentioning.

-----

With all that being said, keep up the good work! I'm becoming a fan now so that I can follow this.
So I went ahead and looked through TBSFrameLib. First of all, nice work! Here are some comments, based on going through it. Note that while I did run the pokemon demo to see it in action, I didn’t spend a lot of time on the code in the demo, as what I’m reviewing is the framework itself :)

Some things I really liked
  • You provide functionality which makes it pretty painless to get things working, for a basic turn-based combat system. Which is exactly what the library sets out to do!
  • Creating a library with hooks to override behavior is great, as it lets the programmer decide how certain functionality should work, possibly making your library applicable for more games than otherwise.


Some things I think could make it awesome:
I feel like the biggest obstacle to using the library, is that its hard to get a grasp for what it does and how, and where. I think it would help to provide a full readme that, without requiring the user to read any of the framework code, would let them know the following:
  • What responsibilities does the library handle for you. What will you need to implement yourself, beyond the scope of the library itself.
  • How does the turn process work, in general terms. Include an image diagram of the flow of combat, for extra crispy coolness. Tools like Gliffy, Creately and LucidChart all let you create flowcharts for free (Although they may put a logo at the bottom).
  • Which procs can I / should I override, and what do they do. In list form, with a brief description for each.

You may also want to consider bundling a demo with the framework itself, and using the __MAIN__ directive, so that if a user runs the framework DME it'll run that demo. Look up __MAIN__ in the F1 reference in Dream Maker, for an example :)

I hope these ideas help you, and most of all: Thanks a lot, for taking the time to write a library that others can benefit from!
I'm glad to see the positive feedback, and ecstatic about the many suggestions. I will definitely be updating the library some more over the next few weeks! No guarantees on when the next update will be, as my job is taking quite a bit of my time lately and I have a personal life as well.
I think it's great he's created a neat library and even more awesome that he's taking critiques and tweaking this library. Albro1 +yea
Updated the library, got quite a bit done. The next thing on the list is better HUD support. I'll be updating the Pokemon Add-on to support this latest update shortly. In the meantime, enjoy the included demo that shows the different types of battle styles!

Go to demo.dm and try changing ALTERNATE_SIDES to ACT_IMMEDIATELY or ALL_INPUT_FIRST.
Pokemon Add-on updated. I'll have the HUD update out as soon as possible for you all. Feedback is always welcome!

NOTE: Once I finish the HUD update I'll be going to town on a full readme for this. So don't worry about that part!
Instead of doing something like this:

map_info/battle_map
z = 2
one_locs = list("2,2")
two_locs = list("2,4", "4,4", "6,4")

Particularly the last two lines, I'd define some objects that can be placed on the map to specify the same information. For example:

battle_info
parent_type = /obj
icon = 'battle-info.dmi'
invisibility = 101

side_one
icon_state = "side-one"

side_two
icon_state = "side-two"

To get these positions at runtime you can use the /Map object:

side_one.locs = map.get(/battle_info/side_one)
side_two.locs = map.get(/battle_info/side_two)

Instead of having to hard-code and remember the locations, you can define these positions in the map editor. If you wanted to make the battle map larger to create a larger border around the outside edge, you might have to update these locations. If the locations are defined by objects placed on the map, when you edit the map you'll move these objects too and they'll remain in the correct places.

I didn't get a chance to look at the updated Pokemon demo yet.
Page: 1 2