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.