NoneType is not subscriptable

Game Object Dependencies

In general it is no good design to work with sensors that are not in the current context. In you case you create a strong relationship to an object called “HotBarSelector”. This means you get in trouble … if there is no such object or there are several objects with the same name.

It is a better design to use the sensors connected to the current controller.

Multi-line Statements

According to PEP008 avoid the usage of "" to spread statements over several lines.
It is recommended to encapsulate the statement in parenthesis (), , {}:


    if (leftMouse.status == bge.logic.KX_INPUT_ACTIVE and
        mouseOver.status == bge.logic.KX_INPUT_ACTIVE and
        rayItem.hitObject == None):

This works for functions, dictionaries, lists.

[Do not worry I used \ at the beginning too, because I did not know about the other option]

Core processing

I recommend to separate condition checks from core processing.

def Tree():
    own = bge.logic.getCurrentController().owner
    selector = scene.objects['HotBarSelector']
    rayItem = selector.sensors['Ray']
    leftMouse = own.sensors['LMouse']
    mouseOver = own.sensors['MouseOver']

    # I prefer to do that in a loop -> I do not need to know the sensor names at that stage
    if (not rayItem.positive and not leftMouse.positive and not mouseOver.positive):
        return 
    
    if rayItem.positive:
        own['health'] -= 1
    else:
        own['health'] -= rayItem.hitObject[rayItem.propName] 
        # either you check and use rayItem or rayDamage, but do not mix both

What you want

This description looks as you want to damage an object. The name “damage” would describe that better than “Tree” (tree is a thing rather than something that gets performed).
The requirements still miss some information -> when should that happen. From the above code I assume:

When the user clicks on an object this object should be damaged. If it is a tree it should be damaged by the damage of the currently hold item otherwise damage by 1.

There is quite some information that needs to be collected:

  • has the user clicked
  • the object clicked on
  • has the player an item
  • if so, the damage value of that item
  • the owner is a tree? what? the tree damages itself?

The last point sounds very strange. Does that means you run that code at a tree?
Are you sure you want to apply damaging logic at each and every single tree in your scene?
I mean imagine what happens when the user clicks the mouse … every tree will run this code at the same frame, but only one will have any effect.

I think I better stop at that point. You need a different perspective on the operation you want to perform.

What I guess you really want

Where to apply that?
The best is at the player, his hands or much better “HotBarSelector” as this looks for trees.

You need both mouse sensors. Switch the mouse over sensor to mouse over any sensor. This way you do not need the ray sensor. I assume your call that sensor [“MouseOver”] as stated in your code.


import bge

def damage():
    'It applies damage on the detected hit object'
    if not allSensorsPositive():
        return

    treeDetector = bge.logic.getCurrentController().sensors["MouseOver"]
    # here we already know this must be positive, see the statement above

    objectToDamage = treeDetector.hitObject
    
    damage = calculateDamage()
    objectToDamage["health"] -= damage # assumed this property exist at the clicked object


def allSensorsPositive():
    'It returns what the name says, making this docstring useless.'
    for sensor in bge.logic.getCurrentController().sensors:
        if not sensor.positive:
            return False
    return True

That should not be that complex isn’t it? Remove the comments and it looks pretty simple.

What you need from here is an implementation of calculateDamage(). I separated it from the above function to be dealt isolated. It has not relationship to how to find the object to be damaged (otherwise we could provide it as argument). Therefore there is no need to mix it with the other operations (and you could call it from somewhere else).

Calculate Damage
A very simple implementation would be this:


def calculateDamage():
    return 1

but you already told what you want:

How about that?


def calculateDamage():
    item = getPlayerItem()
    if item:
        return item["damage"]
    return 1

Unfortunately you did not tell how to get the player’s item or the player. So you need to implement your own version of getPlayerItem(). it should return a game object with an property called “damage”.

Remarks:
The above suggestion works with any object in your scene as long as it gets detected by your mouse over any sensor. You might want to filter the mouse over any sensor by configuring the property field with “health”

I would isolate picking from doing damage,

I just noticed the ‘if empty’ thing,
that is also easy enough,

just have using the item and doing damage successfully set the value ‘Weapon’ back to 1

Are you going for a inventory?
with X number of object 1’s ?? etc

like

10 stones , 3 sticks , 2 axes , 1 Fish ?

Thank you all for the feedback! I love the well of knowldege on this forum. I agree with you guys, I think I’ve been looking at this all wrong.

I have an inventory/hotbar system, all in the same scene as the game, so players can pick up and drag and drop items into their inventory. then use the scroll wheel to select one of any of the hotbar items. This hotbar-scroller can cast a ray to check if you are/arent holding an item, I dont see a problem with using that as my way of detecting the item im holding. but I agree that i need to handle damage differently, Ive got some ideas now thanks to you guys. It will be better this way because I can apply the same scripts to things like rocks to mine, or AI to attack.

Ill give another crack at it today, Ive got a good feeling about with this new information, seriously thank you all!

check this file out

Tab = show overlay to pick value

left click on value = select

UI overlay layer then shows what is selected by moving it with mouse

left click on cube to apply damage

Attachments

UIPickValuePythonApply.blend (526 KB)

Thank you all very much for the help, got it working :slight_smile: