RPG Battle Engine - Alpha 7.5, downloads in first post

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

RPG Battle Engine - Alpha 7.5, downloads in first post

#1 Post by Jake »

Image Image Image
Image Image Image

(Previous thread describing alphas 1-6 can be found here: http://lemmasoft.renai.us/forums/viewto ... =16&t=7207 )

This engine allows you to insert RPG-style battles into your Ren'Py games, supporting FF-style 'active' battles, arbitrary-path-based battles, grid-based, isometric, hex-based and now elevation isometric-tile-based battles.

The system supports many typical RPG features, including a modular skill system, pre-fab skills for melee combat and magical attacks, items and equipment, experience and levelling-up, conditional events, animation and more. All these features are written to be highly customisable to make it easier to tailor the engine to your particular game rules and conventions.

To keep up to date with battle engine development, you may want to subscribe to the newsletter.

A7.5 Files

The latest release can be downloaded here:
battleengine-a7.5.zip (11.4MB Zip)

(The zip is a zipped-up game directory; unzip it to whichever directory you keep your Ren'Py projects in.)

Commercial Licensing

There's now a page on licensing on the battle engine website; you can find it here. If you're releasing your game for free, there's nothing to worry about, it's a standard CC-BY-NC license; if you're interested in talking about a commercial license for your game, then go and read the article and then get in contact:

http://www.eviscerate.net/article/licensing



Previous Releases
Alpha 7 [11.3MB]
Alpha 6 [9.9MB]
Alpha 5 [25MB]
Alpha 4 [25MB]
Alpha 3 [15MB]
Alpha 2 [21MB]
Alpha 1 Windows [11MB]
Alpha 1Mac OSX [15MB]
Alpha 1 Leinnucks [11MB]

License

Image
The battle engine is released under the Creative Commons Attribution Non-Commercial 2.0 UK license. This means that you may use it in and adapt it for your games, but you must a) give due credit, and b) not use it in a commercial project.

I'm perfectly happy to discuss commercial licensing terms if people want to; contact me through PM or via the contact form on my website.

New Features in A7.5

In the latest release - Alpha 7.5 - the following features have been added:
  • Tilemap rotation - view the battlefield from different angles
  • New TileUIProvider to make it easier to customise the square highlight graphic
  • Tilemaps and elevation now work with hex grids
  • Grid and HexGrid Battlefields now use matrix-based projection
  • Supporting the rotation, tiles in a tilemap can have alternate graphics to be used at different rotations, like sprite facing.
  • Various animation fixes, including repeating magic-attack anims and a fixed current-fighter cursor while walking
  • Fighter stats stored as floats, and just rounded upon display
  • Experience bonuses fixed to avoid problems with stat-boosting equipment/effects
  • Haste skill example modified to have a timeout period
  • Sub-skill trees now sort correctly according to weight
  • Special narrator character no longer used for battle announcements, to avoid breaking people's games!
Notes for A7.5
  • UIProvider has been moved out of engine-display.rpy and into its own file in engine-ui.rpy
  • Reset method added to BattlePanner
  • The 'offset' parameter has been removed from GridBattlefield and HexGridBattlefield - it was nearly always set one of two ways, and it's been replaced by an 'isometric' parameter. Set isometric=True to have the isometric grid, and False for a straight perpendicular-to-the-screen rectangular grid. This was done during the changes to use matrix projection for the grids - if you want something different, you'll need to subclass GridBattlefield and write your own projection matrix.
  • The 'offset' parameter has also been removed from the RPGDamage Extra - it wasn't actually being used, it pre-dated the placeMark setting on sprites, and should have been removed several versions ago. If you're still passing it in, though, it'll now break.
  • Subskill trees now sort correctly by weight. Which isn't so much of a 'breaking change' as a 'bugfix', but if you're relying on alphabetical sorting in your subskill trees, you'll need to add weights to the commands now or they won't show in the same order any more.
Feature List
  • 'Active' battle mechanic
  • simple turn-based battle mechanic
  • card-counter wargame battle mechanic
  • FF-style simple face-to-face battlefields
  • Abraxas-demo-style fixed-path battlefields
  • Tactics-style Grid-based battlefields
  • Tilemap-based battlefields with variable height and rotation
  • Hex-grid battlefields
  • Basic enemy AI
  • State-and-facing-aware sprites (so you can have death animations or attack animations or walk in particular directions, etc.)
  • Plug-in skills (so far I've done obvious stuff like 'attack', 'defend', 'skip turn', 'move' and limited magic)
  • Scenery (single and multi-square)
  • Attribute system (e.g. an enemy can have the 'fire' attribute, which makes them weaker to attacks using the 'water' attribute)
  • Highly customisable (pick-and-mix to a degree for non-programmers; very open to customisation and extension for programmers)
  • Items, Inventory and usage
  • Equipment and equip limits
  • Panning
  • Experience and levelling
  • Condition/result event/mission parameter system
  • Equipping, Party-select and Shop screens to facilitate RPG creation
Screenshots

Image Image Image

Image Image Image

Image Image Image
Last edited by Jake on Sat Jan 11, 2014 2:48 pm, edited 5 times in total.
Server error: user 'Jake' not found

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#2 Post by Jake »

Here's an example of setting up a Final-Fantasy-style 'active' battle:

Code: Select all

    python:
        
        battle = Battle(ActiveSchema())

        fieldSprite = BattlefieldSprite('bg woodland')
        battlefield = SimpleBattlefield(fieldSprite)
        battle.SetBattlefield(battlefield)
        
        battle.AddFaction("Player", playerFaction=True)
        
        bobSprite = BattleSprite('bob', anchor=(0.5, 0.75))
        bob = PlayerFighter("Bob", Speed=11, Attack=20, Defence=20, sprite=bobSprite) 
        bob.RegisterSkill(Library.Skills.SwordAttack)
        bob.RegisterSkill(Library.Skills.Skip)
        battle.AddFighter(bob)
        
        geoffSprite = BattleSprite('geoff', anchor=(0.5, 0.8))
        geoff = PlayerFighter("Geoff", Speed=13, Attack=7, Defence=10, MP=20, sprite=geoffSprite)
        geoff.RegisterSkill(Library.Skills.SwordAttack)
        geoff.RegisterSkill(Library.Skills.Skip)
        geoff.RegisterSkill(Library.Skills.Fire1)
        geoff.RegisterSkill(Library.Skills.Water1)
        geoff.RegisterSkill(Library.Skills.Earth1)
        battle.AddFighter(geoff)
        
        battle.AddFaction('Enemies', playerFaction=False)
        
        banditSprite = BattleSprite('bandit', anchor=(0.5, 0.75), placeMark=(0,-75))
        
        bandit1 = SimpleAIFighter("Bandit 1", Speed=10, Attack=15, Defence=8, sprite=banditSprite)
        bandit1.RegisterSkill(Library.Skills.KnifeAttack, 1)
        battle.AddFighter(bandit1)

        bandit2 = SimpleAIFighter("Bandit 2", Speed=10, Attack=15, Defence=8, sprite=banditSprite)
        bandit2.RegisterSkill(Library.Skills.KnifeAttack, 1)
        battle.AddFighter(bandit2)

        bandit3 = SimpleAIFighter("Bandit 3", Speed=10, Attack=15, Defence=8, sprite=banditSprite)
        bandit3.RegisterSkill(Library.Skills.KnifeAttack, 1)
        battle.AddFighter(bandit3)
        
        
        battle.AddExtra(RPGDamage(offset=(0, -75)))
        battle.AddExtra(RPGDeath())
        battle.AddExtra(ActiveDisplay("Player", {"HP": "Health", "Move": "Move", "MP":"MP"}))
        battle.AddExtra(RPGActionBob())
        battle.AddExtra(SimpleWinCondition())
        
        battle.Start()
        
        winner = battle.Won
    
    if (winner == 'Player'):
        "Well done, you beat the bad guys."
    else:
        "Game Over: You Died."
(This is actually one of the demo scripts, just with the copious comments removed.)
Server error: user 'Jake' not found

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#3 Post by CaseyLoufek »

You are awesome. This is one of the best engines I've seen and not just in Ren'py. I'm really looking forward to the height system. You even included a way to get the visible portion off the bat!

Does the height system work with hexes by default?

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#4 Post by Jake »

CaseyLoufek wrote: Does the height system work with hexes by default?
Yes and no? The hex battlefield is based heavily on the grid battlefield, so it will inherit all the intrinsic support for height in the LoS algorithm and the checks in move/pathfinding and so on... but I've not included a hex version of the tilemap battlefield which is easy to set up and draws everything at the right height. I'll be working on it, but since I've not seen anyone using the hex battlefield at all, I figured it could wait 'til the next release...(!)
Server error: user 'Jake' not found

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#5 Post by CaseyLoufek »

I needed to update GetRange in BattleHexGridContoller to get my AIs movement working again. Gonna take a look at setting up a hex grid tilemap myself, I'll let you know how it goes.

Code: Select all

        def GetRange(self, pos1, pos2, callback=None, useHeight=True):
            
            #TODO: use callback to count the actual cost of intervening squares?
            
            dX = max(pos1.X, pos2.X) - min(pos1.X, pos2.X)
            dY = max(pos1.Y, pos2.Y) - min(pos1.Y, pos2.Y)
            
            dist = max(dX, dY)
                
            if useHeight:
                dist = dist + math.fabs(pos1.Height - pos2.Height)
                
            return dist

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#6 Post by CaseyLoufek »

Some very basic files from my proof of concept test. It now works with hexes more or less bug free though I've barely tested it. Fighter Z order may need tweaking.

EDIT: Removed files as it need some work but I've got the basics functioning.

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#7 Post by Jake »

Casey: for what it's worth, I'm part-way through working on tileset and elevation support for hex battlefields myself, if you want to wait for that.

I'll be releasing an Alpha 7.1 soon anyway, as I finally found and fixed a long-standing animation problem last night with the help of PyTom - it turns out that hiding and re-showing a displayable using renpy.show doesn't re-set the animation timebase if you're using an ImageReference around a named image, but passing in a named image directly works fine...
Server error: user 'Jake' not found

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#8 Post by CaseyLoufek »

Actually my last error was because I accidently swapped in an Iso hex (for the X rows offset) tile which of course broke the graphics.

Not perfect but it's more or less working.
Attachments
hex-rock.png
hex-rock.png (12.35 KiB) Viewed 47744 times
elevation.rpy
(20.36 KiB) Downloaded 192 times
engine-battlefields.rpy
(67.66 KiB) Downloaded 210 times

User avatar
Dite
Newbie
Posts: 5
Joined: Sat Sep 15, 2012 11:17 am
Projects: Eight Challengers
Location: Omaha, NE
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#9 Post by Dite »

Hiya, I've been playing with the engine on-and-off for the past week or so, and I'm really happy about how flexible it is. In fact, I tried loading up 20 animated Clydes just to see if the engine could take it, lo and behold: no performance hit. ('Course, ::effort:: to load up 40ish, which is probably the worst I plan on ever trying...)

Question about trying to save in mid-battle: It's just not going to happen, is it? You get a half-rollback that saves stats but resets to the initial state of the battle, or a full reset if you quit and reload. I suspect this is more because of Renpy's saving limitations than anything else, so unless you have any thoughts on this, I think I'm going to have to just disable saving to prevent weird stuff from happening. (Enforced difficulty? Dohohoho.)

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#10 Post by Jake »

Dite wrote: Question about trying to save in mid-battle: It's just not going to happen, is it?
...
I suspect this is more because of Renpy's saving limitations than anything else
Yes and no... it's due to Ren'Py's saving limitations that you get the behaviour that you see, but I suspect that it's probably possible to work around it. I just haven't tried, because I just figured that it was preferable to not be able to save in battles!

Rollback in battles would be a bit more difficult, although I suspect that's also possible if enough work were put into it.



On an unrelated note, here's what I've been working on lately - rotation!
Isometric square grid rotation
Isometric square grid rotation
Hex grid rotation
Hex grid rotation
It unfortunately doesn't work as well as I'd have liked thanks to a limitation of Ren'Py; I'd have preferred that, like the panning controls, the user could rotate at any time. Unfortunately that would require changes to z-order in a transform function, Ren'Py doesn't allow z-order to be governed by a transform, and PyTom has said that it's a fundamental enough thing that it's likely never going to change. So the user can only rotate when an appropriate UI function is called - presently it's implemented in PickTargetPosition, PickTargetFighter and PickFighter, IIRC.

To do this, the GridBattlefield and HexGridBattlefield position-munging has been replaced by matrix transforms, which does mean that it's no longer possible to specify a skewed grid as part of the GridBattlefield construction... but hopefully it's easier to understand what numbers to put where as well, and I don't see a skewed grid being all that useful, so hopefully it's OK...! The advantage is that other view transformations will be easier to implement in the future - I'm thinking of zoom in/out in particular.

I'll release this as soon as I have the extra animations done to have Clyde wandering around a hex map with elevation - which may be as soon as the weekend, depending on finding the time! Since it's mostly fixes and there's no big functional changes, it'll probably be Alpha 7.5 or something...
Server error: user 'Jake' not found

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#11 Post by CaseyLoufek »

Well that defeats the purpose of my IsoHexGrid and HexGrid classes. Not that I'm complaining mind you. :)

Saving in battles? I could make that happen, it might require some special set up for each game though. Rollback? Possible but ugly and not worthwhile I think. Saving in combat can be abused but rollback would be absurd.

Also, is the jumping and heights going to get any more mechanical improvement? As is the system is mostly graphical and not well set up to handle adjusting movement costs and such. Ideally I want options like range getting the Z difference and the X/Y difference and taking the hypotenuse. I can do this myself of course but after seeing your flipping Hex Grid and how busy I currently am I figure I'd ask.

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#12 Post by Jake »

I did tell you I was working on them! ;-) I'd have got this stuff out earlier if I'd just given up on trying to work around the Ren'Py x-order limitation sooner...
CaseyLoufek wrote: Also, is the jumping and heights going to get any more mechanical improvement? As is the system is mostly graphical and not well set up to handle adjusting movement costs and such. Ideally I want options like range getting the Z difference and the X/Y difference and taking the hypotenuse.
Looking at my SVN logs, the jumping-over-gaps part has had a couple of changes since the A7 release:

- Rather than just amending X/Y a second time in the same direction as the first, it now considers as candidates for a jump any position which is a) joined to from the intermediate position and b) not joined to from the start position. This was necessary to get it properly working with hexes, of course, as there are 12 valid candidates from a hex start point, but only 6 directions to move in.
- Jump costs are now based on battlefield range with an extra arbitrary 0.5 penalty rather than just fixed at 2. Firstly this makes them priced more reasonably, secondly the arbitrary penalty makes the jump generally less preferable than just walking when both options are available (such as jumping across diagonals on a square grid, which to my mind should be possible when the two intermediate squares are non-traversable, but looks funny if either of them are).

The idea with the MoveSkill class is that if you want to change the costs associated with moving up or down (or anywhere, for that matter), then you subclass the MoveSkill class and re-implement the GetCallback method to return a new callback function which calculates your costs. The default one will allow movement between +0.5 and -2 height from the current square, and charge it at 1 + (0.5 * difference in height) after allowing a free 0.5 downwards height change before charging extra for it (to make it easier to go downhill than uphill).
The same callback also deals with the way the jumping-across-gaps works - it takes a source square as parameter, and is expected to return a dict mapping all valid squares to move to from the source square to their associated costs from that source square. Another planned feature before I call all this 'more or less finished' is properties or attributes on positions, so certain positions could be marked as 'bog' and cost more movement points to enter, or 'road' and cost fewer, for example; all this would be handled in the callback as well. It's intended to end up as a game-logic method more than an engine method, in the same way that it's intended that people should write their own UIProvider class if they want to change the way that the UI interactions are handled.

I'm not against the idea of adding extra parameters to the MoveSkill initialiser to control some of that - maybe named params for how far up or down a fighter can move and how much up or down movement they get for free - but I don't want to go into too much detail 'cause it's still basically making the assumption that the game-maker even wants to use that model of movement costs. If you can see any way in which the degree of control is still too lacking, let me know and I'll see if I can address it.



The range method (which is used as a base for jump costs) should in both square and hex grids be the 3-dimensional distance between the centre of the ground of the start position and the centre of the ground of the end position. LoS should also function similarly - only in the case of LoS, it will replace "the centre of the ground" with "a point <fighter-height> above the centre of the ground" for any position - source or target - which has a fighter in it.
Server error: user 'Jake' not found

User avatar
Dite
Newbie
Posts: 5
Joined: Sat Sep 15, 2012 11:17 am
Projects: Eight Challengers
Location: Omaha, NE
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#13 Post by Dite »

Oh, no, I think rollback in battle would be a nightmare from a balance perspective. Like, the first thing I did when I cracked the demo open was hammer the rollback button to make sure it wasn't enabled as an oversight or something. Something about the idea horrifies me.

I was just pondering in-battle saving since it's one of those convenience things... Suppose you wanna put the game down and go to bed or something. (I'm pretty laissez-faire about reloading, since the player can use it less if they think it's easymode. Blahblah, opinions about game design.) That said, I flunked most of my flow-related assignments in school and I'm far from understanding enough of the meat about saving to tackle that myself. It's no prob, not losing sleep over it. Thanks for answering!

Other thing: I think I'm just being dumb or something, but I'm using what would be legit-ish syntax for a skill on an item, and it's not recognizing the attribute. No crash, just non-reaction. (I've got it so that I'd get some text if 'stab' is detected, and that piece is working fine on a test skill.)

Code: Select all

Library.Equipment.POINTY = Weapon("POINTY", attributes=['stab'], attack=5, cost=5)
I'm under the impression from engine-items and example-items that this is doable; could you provide a sample of how a weapon with attributes is supposed to look?

CaseyLoufek
Regular
Posts: 142
Joined: Sat May 28, 2011 1:15 am
Projects: Bliss Stage, Orbital Knights
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#14 Post by CaseyLoufek »

Honestly I'm glad I did that Hex class work. My understanding of the inner workings is a lot more complete now and I can write better subclasses.
- Jump costs are now based on battlefield range with an extra arbitrary 0.5 penalty rather than just fixed at 2. Firstly this makes them priced more reasonably, secondly the arbitrary penalty makes the jump generally less preferable than just walking when both options are available (such as jumping across diagonals on a square grid, which to my mind should be possible when the two intermediate squares are non-traversable, but looks funny if either of them are).
This fixes a major part of my concern and I think the other part covers a bug I was seeing on the hex maps.

I'm fine with MoveSkill working as described, just wanting to know if I'd need to be subclassing from another Move class or if it would be in by default or what. I've figured out the callbacks from doing the Hex work and mostly wanted to know how they've been updated as I plan out my game.

One issue I've seen is movement costs differing oddly. I'm chalking this up to the hex jump bug and also the rounding of floats. The height costs are given in floats but they get rounded off when using the default movement ints. So a player can move 2.35 and then 1.15 with 3 points of movement. I'm getting floats in my callback and trying to subtract but I can't seem to get movement to act as a float. I suppose worse comes to worse I can just multiply things by 10 or 100 overall.

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: RPG Battle Engine - Alpha 7, downloads in first post

#15 Post by Jake »

Dite wrote: Oh, no, I think rollback in battle would be a nightmare from a balance perspective
You say that, but the recent-ish PSP re-release of Tactics Ogre: Let Us Cling Together - a classic of the tactical-RPG genre - has added just such a feature! IIRC it lets you roll back something like 30 turns, which is going to be a significant chunk of if not the entire battle. It certainly does make things easier if you want to resort to it, since you can back out of bad decisions or bad luck, but I wouldn't say it's a nightmare. Of course, strictly speaking it's no worse than allowing saving and reloading during battles, since a player could theoretically do that every single turn with every single fighter and revert back to whichever save he wanted...! ;-)

(One big motivator to blocking rollback in battles for me was that I kept doing it by accident during testing, which was rather frustrating since without any extra attention it does the same thing a save and reload would - which generally dumps you back to the beginning of the battle!)
Dite wrote: Other thing: I think I'm just being dumb or something, but I'm using what would be legit-ish syntax for a skill on an item, and it's not recognizing the attribute. No crash, just non-reaction. (I've got it so that I'd get some text if 'stab' is detected, and that piece is working fine on a test skill.)

Code: Select all

Library.Equipment.POINTY = Weapon("POINTY", attributes=['stab'], attack=5, cost=5)
I'm under the impression from engine-items and example-items that this is doable; could you provide a sample of how a weapon with attributes is supposed to look?
The code looks fine - where and how are you checking for the 'stab' attribute? Attributes on equipment are currently only really used in the FighterEquipment classes - for example, the 'hand' attribute will be counted by the HandedFighterEquipment class. They don't come through to attacks like the attributes on attack skills do, because there's presently no link between the equipment and the attack - if all equipment attributes were transmitted to attacks, then your armour would also contribute attributes!

A piece of work I have on my to-do list - which I'll probably get to as part of the next main release, after the minor release I have planned for Very Soon - is to allow equipment items to impart skills. This would mean that, for example, you don't necessarily have to add an Attack skill to your fighter - adding a weapon equip would grant the Attack skill automatically. When this is done, the attributes from the weapon will be passed through that skill, so you can do stuff like create a fire-elemental sword which makes attacks which have the 'fire' attribute.

CaseyLoufek wrote: One issue I've seen is movement costs differing oddly. I'm chalking this up to the hex jump bug and also the rounding of floats.
Certainly there would have been weirdness if you hadn't modified/reimplemented the existing callback at all to work with a hex grid - because hexes aren't continuous in the same axes as the coordinate system, the approach taken in the A7 callback would have - IIRC - covered four of the 12 potential jump candidates and two hexes that should never have been considered! That much is definitely fixed, and I have made a note in my pre-release to-do list to check that move costs aren't being rounded off anywhere. I'm pretty sure I've had it working without rounding - so, say, a fighter can move 4 squares along the flat, for example, but only 3 if there's an upward movement part-way 'cause that upward movement costs 1.25 or something.
Server error: user 'Jake' not found

Post Reply

Who is online

Users browsing this forum: No registered users