Ren'Py Ren'py framework

<Code/>

Newbie
Feb 27, 2020
27
45
I am making an opensource Ren'py framework. It's goal is to make it a lot easier to make amazing looking Ren'py games.

I want idea's from you guys, of what features you want. I am trying to get most of the features done, so you guys can focus more on rendering images and designing the game / script, rather than making and fixing bugs.
For example, on how detailed the framework will be. I already have the time system done.

For the time, I have made two time systems. 24 hour and Times of the day.
24 hour has 1 to 24, and Times of the day, has Morning, Noon, Afternoon, Evening and Night.
They both include The year, day of the month, and weekday name.

It also has the option for making your own time system. But the two above cover most cases.

My goal is to have all the features combined and work very well together. I have other features already planned out like the event system, navigation map, UI etc.

The reason why I need your ideas, is to make sure that my framework can easily accommodate all the different uses, from a visual novel, to a sandbox style game.

You guys can reach me from commenting here, or DM'ing me.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,364
15,281
I want idea's from you guys, of what features you want.
  • An event handler ;
    The game pass by a center point that will automatically test all the defined triggers and call the corresponding scene if the actual game context correspond to one of them.
  • A location system for free roaming ;
    This one is explicit by itself.
  • An advanced notification system ;
    Something prettier than renpy.notify() that permit to have images and to have more than one notification displayed at once.
  • A quest system ;
    Once again explicit by itself.
  • An advanced menu system ;
    Something that don't necessarily display text/text only, but can present the menus as icons or text+icons.
  • A flag system ;
    An easy way to deal with flags.
  • A scheduler for the characters ;
    When entering a given room, you'll be sent to a hub label that will depend of the character(s) present in the room. And their presence will depend of their schedule.
  • A solid, but highly tweakable, combat system ;
    Yet another one that speak for itself.
  • All this being as tweakable than Ren'py ;
    There's really few interest in a Ren'py Framework if it's to make Ren'py games even more lookalike than they already tend to be.
  • All this making a good use of Ren'py's User defined statements.
    There's also really few interest in a Ren'py Framework, if it's to make the development of your game more difficult.

All this being said, by nature Ren'py isn't made for frameworks, or at least for a "big all in one" framework. It's design is opened to extension, and therefore more opened for a modular approach ; you don't use a framework, but include the modules you'll need. What mean that each one of those points above would benefit way more to the authors if they are totally independent, and eventually have more than one version.
Not everyone will need the event handler, but the location system can be interesting for many ; but those people could have absolutely no need for a scheduler.

The approach you should follow isn't, "I'll make a framework", but "I'll extend Ren'py by including few useful statements".
 

<Code/>

Newbie
Feb 27, 2020
27
45
  • An event handler ;
    The game pass by a center point that will automatically test all the defined triggers and call the corresponding scene if the actual game context correspond to one of them.
  • A location system for free roaming ;
    This one is explicit by itself.
  • An advanced notification system ;
    Something prettier than renpy.notify() that permit to have images and to have more than one notification displayed at once.
  • A quest system ;
    Once again explicit by itself.
  • An advanced menu system ;
    Something that don't necessarily display text/text only, but can present the menus as icons or text+icons.
  • A flag system ;
    An easy way to deal with flags.
  • A scheduler for the characters ;
    When entering a given room, you'll be sent to a hub label that will depend of the character(s) present in the room. And their presence will depend of their schedule.
  • A solid, but highly tweakable, combat system ;
    Yet another one that speak for itself.
  • All this being as tweakable than Ren'py ;
    There's really few interest in a Ren'py Framework if it's to make Ren'py games even more lookalike than they already tend to be.
  • All this making a good use of Ren'py's User defined statements.
    There's also really few interest in a Ren'py Framework, if it's to make the development of your game more difficult.

All this being said, by nature Ren'py isn't made for frameworks, or at least for a "big all in one" framework. It's design is opened to extension, and therefore more opened for a modular approach ; you don't use a framework, but include the modules you'll need. What mean that each one of those points above would benefit way more to the authors if they are totally independent, and eventually have more than one version.
Not everyone will need the event handler, but the location system can be interesting for many ; but those people could have absolutely no need for a scheduler.

The approach you should follow isn't, "I'll make a framework", but "I'll extend Ren'py by including few useful statements".
Thanks for the reply. The framework is more or less a group of libraries, however the reason why it's a framework instead of separate libraries is because the libraries will work really well together to make doing certain stuff a lot easier.

Also thanks for the many suggestions,

EVENT SYSTEM
I have already designed an event system, and the event system probably has the most connections with other libraries as events are very dependent of other variables.

CHARACTER LOCATION, SCHEDULE, QUESTS, FLAGS
The character location system has also been designed. In the draft's I have done so far, the location's are predefined on the character class. This makes it easier to do event's on a map, as I can just check character locations, and what event's are currently active, to decide what should be done.

This also make's it easier to do quests, as I just have to check which events and flags are active.
I am looking to make the events / quests system easier to make, by having event/quest lines that have a list of events / quests. This should make it easier for the dev to write separate quest lines, rather than all the events / quests together for each character. I am also looking into a way of having separate quests that aren't connected to a specific character, which would make it easier to do multi character events.

UI CREATION
The UI system is designed to make it easier to create really nice looking UI. Later I will also look into making responsive layouts.

Currently the plan is to have predefined layouts that you combine together to make new and interesting layouts. Most UI's are rows, columns and grids. The UI will make it as easy as possible to combine these to make simple or complicated UI's. To make it easier, I may also make a templating engine, to generate UI components.

NOTIFICATION
Notifications are more or less just temporary UI element's to notify the user of a particular event. And since it's just UI, there will most likely just be a class / function for it. However, they can also be more integrated into the event system, so there is a notification when an event has been completed.

This then could be more integrated, to other systems like the inventory and character relationships.

COMBAT SYSTEM
A modular fighting system can have many things like resources (mana / energy / stamina), randomness, levels, xp, etc.

There also could be different images / animations for each move. Different images if the attack hits or misses etc. So most of the complication come with deciding on how to connect these different things together, while also making it so they are not needed.

Then we may also have different characters or classes that have different move sets, resistances, damage multipliers etc.

I will look into it more deeply and come up with a good way of implementing the modular fighting system.

I think it will most likely be a good thing to have all of the fighting system separate from the rest of the game files, but for it to be called from the script files.

EXTRA STUFF
There are some extra features that I didn't mention in the previous post such as:
- Auto generated walkthrough - For multiple paths, if needed.
- Multiple Versions - You can build the game into multiple versions for easier Patreon support. Or just to have more versions.
- Better build tools and pre-processors for image compression, code obfuscation, tree shaking etc.
- Auto translate support.
- interactive editor in dev mode - edit the script, color code and compress images and write code right in Ren'py.

That's what I have to say for now, thanks for the suggestions. If you have any questions, just ask.
 
  • Like
Reactions: Baka_Energy_studios

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,364
15,281
Thanks for the reply. The framework is more or less a group of libraries, however the reason why it's a framework instead of separate libraries is because the libraries will work really well together to make doing certain stuff a lot easier.
I used the word "module" for a very good reason.
Ren'py is already a framework, put on top of Python/PyGame. Putting another framework on top of it make fewer sense than extending it by the addition of modules. Especially since, like I said, Ren'py is designed with this modularity in mind, while there's not much to help the writing of a framework.
The code of each module can perfectly come in one single piece, but will still be totally independent to each other pieces. This exactly like the core of Ren'py is. You don't need to use layered images to display something on the screen, but the "module" is here and you can use it at anytime, whatever for all your sprites or just some of them. Or you can decide to fake it, either by taking advantage of the text interpolation, or by using the expression property.


EVENT SYSTEM
I have already designed an event system, and the event system probably has the most connections with other libraries as events are very dependent of other variables.
Sorry to say that, but then you are doing it wrong. You are designing your framework with a game (real or imaginary) in mind, taking count of the others elements that will be present and used. This while you should do it with the intent to make it as portable as possible. It's supposed to be here to free the dev, not to lock it up in another place than the original one.
By the way, by doing it this way, you aren't writing a framework, but more writing a template. Not that I have something against this, but like I said this will just make Ren'py games looks even more all the same.

Ideally, using the event system should looks more or less like this :
Python:
# Declaration part for one event
declare event "name_of_the_event":
    trigger  name_of_the_trigger element
    label     name_of_the_label_used
    [called   True || False]
    [priority 0...3]

# Central point of the game
label mainHub:
    #  Will test if an event is triggered and directly branch to it if it's the case.
    eventControl
    #  Default part if there's no events triggered
    call screen LocationMap
With Python being highly Duck Typing oriented, even the trigger part could, and then should, be totally autonomous, depending of what the author feel the more at ease with.
It can be a list of tuples variable_name/value that will be evaluated by the event handler. It can be a function that will return True or False, or it can be an eval string, that will... eval or not.
All this is totally independent to the rest of the framework, the author can then use the event handler with, by example, his own location system (the most likely to be changed). This without the need to firstly make the variables/objects match what is expected by the event handler.

And honestly it's the easiest part of the "framework".
It need more thinking, because this is far to be as flexible as it can seem at first sight, and it's prone to many bugs coming from the person that will use it, but something like this is already a working and independent event handler:
Code:
init python:
    class event( renpy.python.RevertableObject ):
        def __init__( self, name, trigger, label, called=False, priority=1 ):
            self.name = name
            self.trigger = trigger
            self.label = label
            self.called = called
            self.priority = priority

        def triggered( self ):
            retVal = False
            if isinstance( self.trigger, list ):
                retVal = True
                for n,v in self.trigger:
                    if not hasattr( store, n ) or getattr( store, n ) < v:
                        retVal = False
                        break
            elif hasattr( store, self.trigger ) and callable( getattr( store, self.trigger ) ):
                retVal = getattr( store, self.trigger )()
            else:
                retVal = eval( self.trigger )

            if retVal is False:
                return

            store.eventsList[self.priority].remove( self )
            if self.called is True:
                renpy.call( self.label )
            else:
                renpy.jump( self.label )
          
    def eventControl():
        for priority in range( 3, -1, -1 ):
            for e in eventsList[priority]:
                e.trigger()
I wrote it on the fly, so there's perhaps few typos. Sorry if it's the case.

If what you want to write is effectively a framework, and if you effectively want to write it to ease the writing of the game, then it's this kind of code that you should write. Else, like I said, you'll just write a template (what, once again, isn't necessarily something bad) ; something that the dev will have to compose with, filling the blank with his own data. This by opposition to a framework, where the dev will be limited by the boundaries of the code, but still be able to use whatever format inside those boundaries ; exactly like Ren'py already is.

Be noted that, paradoxically, writing it this way would imply less works for you. You are offering the system, having only to take care of the possible errors, but never to care about the structure.
Whatever if the event regard a location, a quest or coffee making. Whatever if the quest rely on a complex class or a standalone variable. This is not the role of your event handler to care about this. It just offer a link between a condition and the consequences of this condition ; whatever can be one and the other.

Passing from the canvas I wrote above to an effectively flexible and robust event handler shouldn't need more than two days ; including the validation and test process. Count a week if you want (and you should) take advantage of the user defined statements.


CHARACTER LOCATION, SCHEDULE, QUESTS, FLAGS
[...] This makes it easier to do event's on a map, as I can just check character locations, and what event's are currently active, to decide what should be done.
You see, it's exactly the problem I talk about ; especially the six last words. It shouldn't be the "framework" that decide what should be done, but the dev, and him only.
An event should be whatever the dev want it to be. Either a game over screen popping up, a variable that will be changed, a quest step that have been reached, a full scripted scene, a character that is now available, a message that pop up on MC's phone, or whatever else can pass through the author's mind. But by making the "framework" decide (whatever how lax can be the definition of the word) what should be done, you lock the dev inside your own logic, offering him only the possibilities you thought about.
Once again, by itself it's not necessarily bad, just different.


This also make's it easier to do quests, as I just have to check which events and flags are active.
While you shouldn't care at all about their evolution:
Code:
declare quest "name of the quest"
add stage "quest name":
     name "name of the stage"
     condition Some_condition (same way than the event triggers)
    [action what_will_be_done]
[...]
add stage "quest name":
    name "name of the stage"
    condition Some_condition (same way than the event triggers)
    [action what_will_be_done]
Your own code should just test the condition of the actual stage. Then, if those conditions are reached, pass to the next stage and proceed the action if there's one ; because the quest can be purely internal, helping the dev to keep track of the game evolution :
Code:
menu coffeeshop:
    "Hi, how are you ?":
        [...]
    "I want a latte please":
        [...]
    "I search a job" if quest.angryMom.stage == 2:
        [...]
    "Work" if quest.angryMom.stage > 4:
        [...]
I know that I'm a little rude, but, and I insist on this, it doesn't mean that I'm against your idea. Just that you need to understand that there's a difference between what you promote (a framework to help people write Ren'py games) and what you are effectively making (a template to help people write a game that will react in few predefined ways).
And also, as I said more than once, it's not a problem if it end being a template. It would anyway at least show other perspectives to the authors.


NOTIFICATION
Notifications are more or less just temporary UI element's to notify the user of a particular event. And since it's just UI, there will most likely just be a class / function for it.
It's really limited, at least presented like this. And it also offer nothing more than what Ren'py already do with its own renpy.notify() function.

I don't really know where, but there's a notification system I wrote, more or less on the fly, that is available here. It permit to have one or more notification shown at once, and to use, or not images. But while being something really short, it obviously need more than just a class / function. From memory, there's three functions, one class, one list and one screen, plus few gui variables. This for what is probably around 50 lines of code.
Encapsulate this into a user defined statement, and you've something both powerful, easy to use, and totally independent, that would looks like:
Code:
label whatever:
    [...]
    notify "text of the notification"
    [...]
    notify "another text" icon

Then we may also have different characters or classes that have different move sets, resistances, damage multipliers etc.
It shouldn't be your concern.

The problem is rarely the computation by themselves, but the logic. What prevent more authors to have a combat system in their game isn't that they don't know how to subtract the damage from the health, or how to know if the player have been hit. No, it's that they don't know how to link them together. And this apply for all the other elements that are the event handler, the quest system and so on.
The role of a framework isn't to provide the computations (it's the role of a template), but to provide the logic ; to link the different elements together. And like I said, Python being highly Duck Typing compliant, what those elements are isn't really important.

Code:
screen combatMap():
    for o in opponents:
        use combatOpponent( o )

    use combatUI

screen combatOpponent( o ):
    imagebutton:
        idle o.image
        action SetVariable( "selectedOpponent", o.id )

screen combatUI():
    vbox:
        "attack":
            action Function( mc.hit, selectedOponent )
        "defend":
            action Function( mc.defend )
This is the logic, this is what link the elements together. Therefore, this is what your frameworks should looks like.

Make the default class for the opponent and for the player. Give them the attributes and methods needed by this default approach, and fill them with default computation :
Code:
class Combat( renpy.python.RevertableObject ):
    def __init__( self, health, damage, armor ):
        [...]
    def isHit( self, attack ):
        return attack > self.armor
    def isDead( self ):
        return self.health <= 0
    def hit( self, damage ):
        self.health -= damage
[...]
Then let the dev either limit to this default system, or extend it with his own ideas :
Code:
class MyCombat( Combat ):
    def __init__( self, ... )
        [...]
    def isHit( self, attack ):
        return attack > ( self.shield - self.curse )
    def hit( self, damage ):
        self.health -= damage - self.armor
    def changeWeapon( self, weapon ):
        self.damage = weapon.damage
If you go a little further than a single attack that always do the same amount of damage, by example by offering the possibility to have two attacks, one weak and one strong, or by offering the possibility to equip different kind of weapon, then the dev will also have all the code he need to do the combat the way he want. He'll just have to mimic what you did, passing by a small trial and error phase, to adapt your framework to his own need.
But once again, the way he want to do the combat shouldn't be your concern. It can have magic or not. It can be close combat or range combat. It can be with or without weapons. All this don't matter for your framework.


- Auto translate support.
What do you have against Ren'py built-in translation ? :/



Edit: Wow, there were a big error in the format, making not totally evident to see what was quoted and what I said. Sorry for that and to not have seen it earlier.
 
Last edited: