Ren'Py Image displayed in notification

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
923
3,925
Hi guys,

I am having an issue in figuring out how to make a notification display text + image.
For the notifications I use:
Code:
$ renpy.notify(" Text")
If I put a variable, even in the text, it will display the actual variable not what it defines.
Ex:
For
Code:
$ renpy.notify(" Text [vr]")
It will display: Text [vr]

Regarding this, I would like to add an image in the notification, besides the text. Can anyone help?

Thank you!
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
923
3,925
Maybe giving a little more information... how do you define the variable vr? what error does the daz show you?
Code:
define [vr] = Character ("Var")
If I use in the script.rpy the
Code:
$ renpy.notify(" Text [vr]")
In game will display the notification with: text [vr] not text Var

If I use in the script.rpy the
Code:
$ renpy.notify(" Text " vr )
It will crash at boot and it will display :
Code:
I'm sorry, but errors were detected in your script. Please correct the
errors listed below, and try again.


File "game/script.rpy", line 876: invalid syntax
    renpy.notify(" Text." vr)
                                                       ^
  

Ren'Py Version: Ren'Py 7.1.3.1092
Sun Jan 27 18:43:15 2019
Most likely because I didn't use [vr] instead of vr.

If I use in the script.rpy the
Code:
$ renpy.notify(" Text " [vr] )
It will display and error:
Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 876, in script
    $ renpy.notify(" Text." [vr])
  File "game/script.rpy", line 876, in <module>
    $ renpy.notify(" Text." [vr])
TypeError: string indices must be integers

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 876, in script
    $ renpy.notify(" Text." [vr])
  File "D:\renpy-7.1.0-sdk\renpy\ast.py", line 881, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "D:\renpy-7.1.0-sdk\renpy\python.py", line 1913, in py_exec_bytecode
    exec bytecode in globals, locals
  File "game/script.rpy", line 876, in <module>
    $ renpy.notify(" Text." [vr])
TypeError: string indices must be integers

Windows-8-6.2.9200
Ren'Py 7.1.3.1092
Vis 0.2
Sun Jan 27 18:45:47 2019
 

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,705
Are you tried using "default" instead of "define"?
Code:
default [vr] = Character ("Var")
 

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,705
Ok, I've done several tests and in the end (Eureka!), it works...

Try this:

Define your character
Code:
define vr = Character("Var")
Create this screen:
Code:
screen notify(message):
    text "Text [vr]"
Use this code to show your notification:
Code:
$ renpy.notify("text")   #I think it's not important what you write between "
With this, if you want to test it, it has to work... another question is if you need to change this in other notifications, now I do not have time to do more tests but sure that some of the gurus in this forum gives you a better solution :p
 

Epadder

Programmer
Game Developer
Oct 25, 2016
568
1,064
I would recommend you don't use brackets in your naming conventions...

In Ren'py's scripting language "[somevariable]" is asking Ren'py to display the value of that variable as a string. Of course that won't work in a python command (anything with $ preceding it is python). For that you need to use python string /

Regardless I don't think the standard renpy.notify will actually display an image.

You will have to make a custom version of the notification, as an example here's the one I'm using to have multiple notifications that clear themselves.

Functions:

Python:
    def uifunction_PopNotification():
        store.uidisplay_NotificationsToDisplay.pop(0)

    def internalfunction_AddNotification(message):
        if len(store.uidisplay_NotificationsToDisplay) < 1:
            store.uidisplay_NotificationsToDisplay.append(message)
        elif store.uidisplay_NotificationsToDisplay[0] == "None":
            store.uidisplay_NotificationsToDisplay[0] = message
        else:
            store.uidisplay_NotificationsToDisplay.append(message)

    def uifunction_CustomNotification(message):
        internalfunction_AddNotification(message)
        renpy.show_screen("screenlabel_CustomNotifications")
Screen:
Python:
screen screenlabel_CustomNotifications():
    zorder 100
    style_prefix "notify"
    vbox:
        xalign 0.0
        yalign 0.0
        spacing 0
        for messages in uidisplay_NotificationsToDisplay:
            frame at notify_appear:
                text "[messages]"

    if len(uidisplay_NotificationsToDisplay) > 1 and len(uidisplay_NotificationsToDisplay) < 7:
        timer 0.75 action Function(uifunction_PopNotification) repeat True
    elif len(uidisplay_NotificationsToDisplay) >= 7 and len(uidisplay_NotificationsToDisplay) < 25:
        timer 0.35 action Function(uifunction_PopNotification) repeat True
    elif len(uidisplay_NotificationsToDisplay) >= 25:
        timer 0.15 action Function(uifunction_PopNotification) repeat True
    else:
        timer 2.0 action [Hide('screenlabel_CustomNotifications'),SetVariable("uidisplay_NotificationsToDisplay", ['None'])]
I use $ uifunction_CustomNotification("Some String") when I need to give feedback to the player, the $ internalfunction_AddNotification() has a little bit of redundant code from when I was trying to figure out how to do that.
 
  • Like
Reactions: Porcus Dev

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
Functions:
Isn't it too much ?

Code:
screen notifyEx( msg=None, img=None ):

    zorder 100
    timer 3.25 action Hide('notifyEx')

    frame at notify_appear:
        if not msg is None:
            text msg
        if not img is None:
            add img


label start:
    show screen notifyEx( msg="abcd" )
    "blabla"
    show screen notifyEx( img="abc.jpg" )
    "blibli"
    show screen notifyEx( "abcd", "abc.jpg" )
    "bloblo"
A little touch of styling and it's done.
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
923
3,925
Isn't it too much ?

Code:
screen notifyEx( msg=None, img=None ):

    zorder 100
    timer 3.25 action Hide('notifyEx')

    frame at notify_appear:
        if not msg is None:
            text msg
        if not img is None:
            add img


label start:
    show screen notifyEx( msg="abcd" )
    "blabla"
    show screen notifyEx( img="abc.jpg" )
    "blibli"
    show screen notifyEx( "abcd", "abc.jpg" )
    "bloblo"
A little touch of styling and it's done.
By all the gods, it worked. Thank you!
 

Epadder

Programmer
Game Developer
Oct 25, 2016
568
1,064
@anne O'nymous - For my project I felt it necessary, you quickly run into situations where you could receive a lot of notifications about things going on in the world / After-battle. I was originally going to take the messages and try and parse them into blocks for duplicate messages like "A day has passed (x3)", but I found that the notifications ended up not being very timely/confusing to follow.

I also tend to make "wrapper" functions at times just to make another function easier for me to keep track of. :whistle:

An example of the start of a busy week after skipping a week.
extremenotification.jpg
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
A little off topic from your original question... but you seem to be getting awfully close into my current pet gripe... mixing defined characters and variables to store that character's name.

define is intended to set a variable who's value never changes. What might be termed a CONST in other programming languages.

define e = Character("Eileen") being a variable e that is of type Character

Python:
define m = Character("Mom")

label start:

    scene black
    m "My name is [m]"
    return
Does indeed work. Despite m not actually being a text object.

But I'm seeing more and more of this lately... and it's just a minefield.
Python:
define m = Character("Mom")

label start:

    scene black
    $ m = renpy.input("Mom's name?")
    m "My name is [m]"
    return
The $ m = renpy.input completely breaks the original Character object.
I've came across it with someone and broken side images. But I believe it's also caused infinite loops and other really odd things to happen.

The correct answer being something more like this...
Python:
define m = Character("[m_name]")
default m_name = ""

label start:

    scene black
    $ m_name = renpy.input("Mom's name?")
    m "My name is [m_name]"
    return
My bad if you weren't headed down this route...
I just get twitchy recently when I see anything that looks like vr "My name is [vr]", especially since you followed up in a reply by giving the example of define vr = Character ("Var")
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
923
3,925
A little off topic from your original question... but you seem to be getting awfully close into my current pet gripe... mixing defined characters and variables to store that character's name.

define is intended to set a variable who's value never changes. What might be termed a CONST in other programming languages.

define e = Character("Eileen") being a variable e that is of type Character

Python:
define m = Character("Mom")

label start:

    scene black
    m "My name is [m]"
    return
Does indeed work. Despite m not actually being a text object.

But I'm seeing more and more of this lately... and it's just a minefield.
Python:
define m = Character("Mom")

label start:

    scene black
    $ m = renpy.input("Mom's name?")
    m "My name is [m]"
    return
The $ m = renpy.input completely breaks the original Character object.
I've came across it with someone and broken side images. But I believe it's also caused infinite loops and other really odd things to happen.

The correct answer being something more like this...
Python:
define m = Character("[m_name]")
default m_name = ""

label start:

    scene black
    $ m_name = renpy.input("Mom's name?")
    m "My name is [m_name]"
    return
My bad if you weren't headed down this route...
I just get twitchy recently when I see anything that looks like vr "My name is [vr]", especially since you followed up in a reply by giving the example of define vr = Character ("Var")
I did a stupid thing like that and I ended up into a loop with the main character. Now I use something like this:


Script.rpy
Code:
$ j = renpy.input("Name the main character:")
    $ j = j.strip()
Variables.rpy:
Code:
define nickname = Character("[j]")
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
Normally I don't do that, what's asked in my PM box is answered in it. But for once I'll make an exception, because it can also interest @Epadder .

So, here's a variation of the code I gave yesterday. Except that it let you stack multiple notifications. They all have their own timer, so will disappear progressively, and as before, they let you have an image, an image and text, or just a text.

Code:
init python:

    class NotifyEx( renpy.python.RevertableObject ):
        def __init__( self, msg, img ):
            super(NotifyEx, self).__init__()
            self.msg = msg
            self.img = img
            self.remain = gui.notifyEx_delay


    def notifyEx( msg=None, img=None ):
        notifications.append( NotifyEx( msg, img ) )
        if len( store.notifications ) == 1: renpy.show_screen( "notifyEx" )


    def notifyExClean( value ):
        if value in store.notifications: store.notifications.remove( value )
        if len( store.notifications ) == 0: renpy.hide_screen( "notifyEx" )



# Delay of visibility of a notification.
define gui.notifyEx_delay = 10.0
# Width of the images.
define gui.notifyEx_width = 64
# Height of the images.
define gui.notifyEx_height = 64

default notifications = []

style notify_text is default:
    color "#FF0000"
    yalign 0.5

style notify_hbox is default:
    ysize gui.notifyEx_height

screen notifyEx():

    zorder 100

    style_prefix "notify"

    vbox:
        for d in notifications:
            use notifyExInternal( d )
            # aerate a little.
            null height 5


screen notifyExInternal( n ):

    style_prefix "notify"

    frame at notify_appear:
        hbox:
            if not n.img is None:
                add n.img
            else:
                # Ensure that all the texts will be aligned.
                null width gui.notifyEx_width

            # aerate a little.
            null width 5

            if not n.msg is None:
                text n.msg

    timer 0.05 repeat True action [ SetField( n, "remain", n.remain - 0.05 ), If( n.remain <= 0, Function( notifyExClean, n ), NullAction() ) ]


label start:

    $ notifyEx( msg="abcd" )
    "blabla"
    $ notifyEx( msg="efgh", img="efgh.jpg" )
    "bloblo"
    $ notifyEx( img="ijkl.jpg" )
    "blibli"
 

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,705
Normally I don't do that, what's asked in my PM box is answered in it. But for once I'll make an exception, because it can also interest @Epadder .

So, here's a variation of the code I gave yesterday. Except that it let you stack multiple notifications. They all have their own timer, so will disappear progressively, and as before, they let you have an image, an image and text, or just a text.

Code:
init python:

    class NotifyEx( renpy.python.RevertableObject ):
        def __init__( self, msg, img ):
            super(NotifyEx, self).__init__()
            self.msg = msg
            self.img = img
            self.remain = gui.notifyEx_delay


    def notifyEx( msg=None, img=None ):
        notifications.append( NotifyEx( msg, img ) )
        if len( store.notifications ) == 1: renpy.show_screen( "notifyEx" )


    def notifyExClean( value ):
        if value in store.notifications: store.notifications.remove( value )
        if len( store.notifications ) == 0: renpy.hide_screen( "notifyEx" )



# Delay of visibility of a notification.
define gui.notifyEx_delay = 10.0
# Width of the images.
define gui.notifyEx_width = 64
# Height of the images.
define gui.notifyEx_height = 64

default notifications = []

style notify_text is default:
    color "#FF0000"
    yalign 0.5

style notify_hbox is default:
    ysize gui.notifyEx_height

screen notifyEx():

    zorder 100

    style_prefix "notify"

    vbox:
        for d in notifications:
            use notifyExInternal( d )
            # aerate a little.
            null height 5


screen notifyExInternal( n ):

    style_prefix "notify"

    frame at notify_appear:
        hbox:
            if not n.img is None:
                add n.img
            else:
                # Ensure that all the texts will be aligned.
                null width gui.notifyEx_width

            # aerate a little.
            null width 5

            if not n.msg is None:
                text n.msg

    timer 0.05 repeat True action [ SetField( n, "remain", n.remain - 0.05 ), If( n.remain <= 0, Function( notifyExClean, n ), NullAction() ) ]


label start:

    $ notifyEx( msg="abcd" )
    "blabla"
    $ notifyEx( msg="efgh", img="efgh.jpg" )
    "bloblo"
    $ notifyEx( img="ijkl.jpg" )
    "blibli"
Hi @anne O'nymous,

Nice code, thanks for putting it on the forum (y)

I'm trying to use it in my game and it's working well, but I have a small problem with the images, they don't resize to the same size and this makes the notification windows very variable.

I tried to use the parameters "gui.notifyEX_width" or ""gui.notifyEX_height" but it doesn't work for me, I only managed to change the part of the text but the images are still shown according to their original size... Is there any way to force the images to be shown all with the same size?
(I could create duplicates of the images with the same size, but I'm sure there must be some way to do it with the ones I already have in the game so I don't duplicate unnecessary things).

Thank you in advance! ;)

EDIT: BTW, I would also like to know if there is any way to force the notification to disappear before the set seconds; I suppose it will be using the command "notifyExClean" but I'm not sure how to use it in the middle of the dialogue, thank you very much.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
I tried to use the parameters "gui.notifyEX_width" or ""gui.notifyEX_height" but it doesn't work for me, I only managed to change the part of the text but the images are still shown according to their original size... Is there any way to force the images to be shown all with the same size?
What you are looking for is :
[Note: I can't test right now, so the code is given "as it"]
Python:
screen notifyExInternal( n ):
[...]
            if not n.img is None:
                add im.Scale( n.img, gui.notifyEx_width, gui.notifyEx_height )
But that will force the icon to now have dimensions not necessarily proportional to the original size. So, if it's a problem, use the fact that I don't enforce the type for the NotifyEx parameters :
Python:
image iconThis = im.Scale( "images/icons/this.jpg", 100, 90 )
[...]
label blabla:
    $ notifyEx( msg="something", img=iconThis )

EDIT: BTW, I would also like to know if there is any way to force the notification to disappear before the set seconds; I suppose it will be using the command "notifyExClean" but I'm not sure how to use it in the middle of the dialogue, thank you very much.
The problem with notifyExClean here is that you need to provide the value to remove. It can be done by enumerating the list :
Python:
for a in notifications:
    notifyExClean( a )
but it's too much for such a thing. Just reset the list and it's good :
Python:
init python:

    def notifyExPurge():
        store.notifications = []
        renpy.hide_screen( "notifyEx" )

[...]
label blabla:
[...]
    "Pfff, we are still alive"
    $ notifyExPurge()
    "Yeah, it was close this time"
 

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,705
What you are looking for is :
[Note: I can't test right now, so the code is given "as it"]
Python:
screen notifyExInternal( n ):
[...]
            if not n.img is None:
                add im.Scale( n.img, gui.notifyEx_width, gui.notifyEx_height )
But that will force the icon to now have dimensions not necessarily proportional to the original size. So, if it's a problem, use the fact that I don't enforce the type for the NotifyEx parameters :
Python:
image iconThis = im.Scale( "images/icons/this.jpg", 100, 90 )
[...]
label blabla:
    $ notifyEx( msg="something", img=iconThis )



The problem with notifyExClean here is that you need to provide the value to remove. It can be done by enumerating the list :
Python:
for a in notifications:
    notifyExClean( a )
but it's too much for such a thing. Just reset the list and it's good :
Python:
init python:

    def notifyExPurge():
        store.notifications = []
        renpy.hide_screen( "notifyEx" )

[...]
label blabla:
[...]
    "Pfff, we are still alive"
    $ notifyExPurge()
    "Yeah, it was close this time"
Brilliant!!

I'll try it and I'll tell you.

Thank you so much! ;)