Random events via objects and methods?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Message
Author
DoubleProlix
Regular
Posts: 33
Joined: Thu Oct 19, 2017 8:04 pm
Contact:

Re: Random events via objects and methods?

#16 Post by DoubleProlix » Fri Nov 03, 2017 7:46 pm

Have you perhaps considered a factory or dispatcher style pattern? Personally I'd edge toward one overlord class that just holds and spawns sub classes for events, basically a handler or over-seer class. Init that in a 0 or -1 offset and just register/amend/delete events from that. Ren'py should have no probs saving/loading that.
How would I implement this?
What init offset are you using?
The class is defined in init -1. The only other init I have is not at an offset, it's just init.
How do you interact with the object?
I just call the chooseEvent method with the value of the type of event I want to choose from.

Code: Select all

$ chooseEvent('officeEvent')
So all the event objects are defined with three properties, the event type, whether or not the event is active, and the label of the event's processing.

Code: Select all

default patrolEvent_default_Obj = Event ('patrolEvent', 'True', 'patrolEvent_default')
This instance of Event is a patrolEvent, it is active, and choosing it jumps to patrolEvent_default.

The objects themselves are just placed in separate .rpy files sorted by event type, paired by the above object and the label that object calls when chosen by the chooseEvent method.

Code: Select all

def chooseEvent(type): 
            list = []
            for obj in Event.getinstances():
                if eval(obj.isActive) and obj.triggered == False and obj.eventType == type:
                    list.append(obj)
            if len(list) == 0:
                return(False)
            else:
                renpy.call((renpy.random.choice(list)).doEvent)
                return(True)
Now, the first time the game is run everything works as I expect it to. I go to the office (for example), I call chooseEvent(officeEvent), and it sorts all of the Event instances that are active, not triggered, and match eventType into a list. It then picks one of those events and calls that event's doEvent, jumping to its label.

However, after loading... nothing happens. I'm guessing that len(list) returns zero, and chooseEvent returns (False) instead of calling doEvent, because the game just continues to the next code block.

If that's true, then for some reason all of the Event objects either disappear, or all their isActive turn False, or all their triggered turn true, or all their eventTypes turn into smoke.
Current Project: Thaumarotica - an occult erotic thriller
SubscribeStar - Patreon - Itch.io

DoubleProlix
Regular
Posts: 33
Joined: Thu Oct 19, 2017 8:04 pm
Contact:

Re: Random events via objects and methods?

#17 Post by DoubleProlix » Fri Nov 03, 2017 8:11 pm

I think that using weakref to simulate a Singleton pattern might not be pickle-able...
Is there a way to do what I'm trying to go for in a manner more pickleable?
Current Project: Thaumarotica - an occult erotic thriller
SubscribeStar - Patreon - Itch.io

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Random events via objects and methods?

#18 Post by Remix » Fri Nov 03, 2017 8:20 pm

DoubleProlix wrote:
Fri Nov 03, 2017 7:46 pm
Have you perhaps considered a factory or dispatcher style pattern? Personally I'd edge toward one overlord class that just holds and spawns sub classes for events, basically a handler or over-seer class. Init that in a 0 or -1 offset and just register/amend/delete events from that. Ren'py should have no probs saving/loading that.

How would I implement this?
Basically, in an low init python block you would define and initialize an over-seer class...

Code: Select all

Pseudo code --- to give an idea 

init -1 python:
    class OverSeer( object ):
    
        def __init__( self ):
            self.events = []
            
        def add_event( self, event ):
            # probably with a test to see if there already
            self.events.append( event )
            
        def get_random_event( self, event_type ):
            return random.random.choice( [ k for k in self.events if type( k ) == event_type ] )
            
    # initialized ready - allowing us to reference the class as 'overseer' in script
    overseer = OverSeer()
            
    class OfficeEvent( baseEvent ):
        # etc etc
    
.
.
.
 
somewhere in code
$ overseer.add_event( officeEvent( some params ) )

.
.

somewhere wanted
$ renpy.jump( overseer.get_random_event( type( officeEvent ) ).jumpEvent )
Basically the OverSeer class holds and governs all the different Events. With all those held in its scope it can then handle all the choosing, prioritizing, managing etc quite easily

A dispatcher pattern is very similar except rather than passing an object into add_event you would just pass parameters and the method itself would deduce which object type to spawn and use

You could still use your current event classes, just use overseer to manage them

I hope that gives an idea of a way to 'maybe' get things running smoother
Frameworks & Scriptlets:

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Random events via objects and methods?

#19 Post by Remix » Fri Nov 03, 2017 9:06 pm

On an aside (and in a self-promotional aspect (and a 'someone has to give feedback on the class sort of thing)) you might find Event Handler with Lexer interesting (certainly if your game does not involve translations as yet)

It would allow you to:

Code: Select all

label fix_photocopier:
    event register:
        function:
            test_location [ 'office' ]
Then just define a true/false python function

def test_location( location ): return current_location == location

and the event would register as available if true

Your random logic then basically does
$ current_location = 'office'
$ renpy.jump( renpy.random.choice( event_handler.get_label_names_for_minute() ) )

No huge need to use the time/date event settings if not needed
Frameworks & Scriptlets:

DoubleProlix
Regular
Posts: 33
Joined: Thu Oct 19, 2017 8:04 pm
Contact:

Re: Random events via objects and methods?

#20 Post by DoubleProlix » Fri Nov 03, 2017 9:23 pm

Well, what I was originally trying to do was set up events as objects, with each object having a method called to evaluate whether or not the event was currently valid (returning True or False) and a method to be executed when the event triggered.

When an event was required, the handler would make a list of all objects of the correct event class that were currently valid, then pick one.
Current Project: Thaumarotica - an occult erotic thriller
SubscribeStar - Patreon - Itch.io

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Random events via objects and methods?

#21 Post by Remix » Fri Nov 03, 2017 10:07 pm

Part of my ToDo list on the EventHandler is to abstract the event conditions as objects - the main snaggle being the lexer/parser recognizing the parameters those objects might hold.

At the moment it internally handles all time based conditions and externalizes the rest through functions or store/retrieve unknown keywords (for extensibility). This does allow someone to define an event with a condition that the handler is not aware of (basic examples being 'location', 'money', 'affection level' etc) though it would be far more elegant to define a BaseCondition class to extend ad-hoc and have the handler dispatch those after interpreting the lexer/parse.
The crux is that the parser has to register events (labels) at init in a python early (basically before any 'init -infinity python' runs, during the time Ren'py reads and rationalizes the game script and dialogue) so they exist before ever needed. To sub-class the conditions means either defining them prior to that and have them tell the lexer which codewords they are looking for or allow the lexer to read anything (without testing or sanity) and just throw that at the handler.

Anyway (tl;dr)...
Using python functions to evaluate valid/invalid events does appear to offer the facility you desire... just maybe not as elegant
Frameworks & Scriptlets:

Post Reply

Who is online

Users browsing this forum: No registered users