Page 1 of 1

Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Thu Aug 17, 2017 1:24 pm
by Alem
Greetings! I'm tinkering around VN/Management hybrid idea with some group-based combat based on this tutorial. So far the prototype progresses nicely with few exceptions, which I hoped to clear up with community's help. I don't think posting all the code here is wise - it'll be a huge blob of text, so here's Renpy project folder for details.

1) I prepared a method for combat groups to inflict damage to their opponents, you can check it out here as a proof of concept. The function works fine in the external IDE, but if I try to use it in combat screen (start the project -> begin sortie button, then engage button) Renpy crashes with TypeError: 'NoneType' object is not callable. The full log is in the attached archive. I think Python tries to work with a blank object and fails, but which one?

2)Showing screens force them to execute methods inside the button code block even if normally this would require the player to click on a button to activate these. I noticed it after including time.sleep(5) inside the deal_damage function for the fleet. The game pauses for the marked time before shoving the combat screen yet it must fire only then the button is pressed. Is there a way to forbid such behavior and execute methods on buttons only if the button is clicked?

Thank you!

Re: Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Fri Aug 18, 2017 2:57 pm
by Alem
I guess the code may help :/

Code: Select all

init -1 python:
    import renpy.store as store
    import renpy.exports as renpy
    import random
    import time

    targets = []
    target = None
    stopbattle = 0

    class Fleet(store.object):
        def __init__(self,speed="Fast"):
            self.items = []
            self.speed = speed
        def add(self, item): # a simple method that adds an item; we could also add conditions here (like check if there is space in the inventory)
            self.items.append(item)
            
        def deal_damage(self, enemyfleet):
            targets=[]
            time.sleep(1)
            for item in enemyfleet.items:
                if item.hp > 0:
                    targets.append(item)
            if len(targets) == 0:
                stopbattle=1
            else:
                for item in self.items:
                    if item.hp > 0:
                        damage = item.damage + renpy.random.randint(0,5)
                        target = renpy.random.choice(targets)
                        target.hp = target.hp - damage
                    else:
                        stopbattle=2
The rest is omitted. The problem I have is in the deal_damage method, which is called like this as a test:

Code: Select all

screen combat_screen:
	textbutton ("Engage") action Function(fleet.deal_damage(enemyfleet)) xpos .430 ypos .85
The sleep timer fires off at the moment I enter the screen and clicking on the engage button crashes with Renpy TypeError: 'NoneType' object is not callable. Am I using the code in wrong way, any thoughts?

Re: Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Fri Aug 18, 2017 3:25 pm
by Remix
Function() is actually an interpolated call so it needs parameters rather than a stringlike call

Function( fleet.deal_damage, enemyfleet )

Re: Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Fri Aug 18, 2017 4:26 pm
by Alem
Thanks, Remix. Worked like a charm after your fix. Strangely enough, another screen used the same incorrect input for Function() with parenthesis and gave the results regardless.

Re: Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Fri Aug 18, 2017 4:41 pm
by Remix
Your 'fleet.deal_damage' function has no return, so basically returns None...
When Ren'py does Function(fleet.deal_damage(arg)) it calls that first parameter (which is effectively the return value of the function), so effectively tries to call type(None).__call__() hence the error "TypeError: 'NoneType' object is not callable"
If a function returned something, a string, a dict, an object, the Function call would then try to call that, so could work

val = 0
def a(): val += 1
def b(): return a
Function(b()) ...
val -> 1

Something like that anyway

Re: Code questions. Renpy crash with TypeError: 'NoneType' object and strange button code behaviour

Posted: Sat Aug 19, 2017 6:09 am
by Alem
Remix wrote: Fri Aug 18, 2017 4:41 pm Your 'fleet.deal_damage' function has no return, so basically returns None...
When Ren'py does Function(fleet.deal_damage(arg)) it calls that first parameter (which is effectively the return value of the function), so effectively tries to call type(None).__call__() hence the error "TypeError: 'NoneType' object is not callable"
If a function returned something, a string, a dict, an object, the Function call would then try to call that, so could work

val = 0
def a(): val += 1
def b(): return a
Function(b()) ...
val -> 1

Something like that anyway
Oh, now I get it. Yeah, you are right, the other function used inventory slots to swap between two lists and returned the result. With damage method, I wanted to troubleshoot it step by step until I stumbled on this problem. Ironically, I needed to go ahead and finish it before any real testing.

Thanks again!