Creating a message list

hay everyone …
its been a while !!!
so i have been expermenting and learninig python scripting all this time , and i have been into a not bad level of controling and creating thing in BGE
but resaintly i faceds a problem which i really need to solve !!!
so i manged to creat a collission sensor that can detect whatever number property,s that i want using one collission sensor.
and i created an objectHitList like this ,

so i am using an old BGE , its a long story. but i just want to make sure things dont get mixedup

actu_collide = cont.sensors[“collision_sens”]
for ob in actu_collide.objectHitList:
# Check to see the object has this property
if “hit1” in ob:
own[“life”] -=1
if “hit2” in ob:
own[“life”] -=2

but now i want to creat a message sensor that does tha same,
i have alot of messages that i need to reseve , and i cant keep adding alot of sensors like the old way !

i tryed to make the same approch useing the same way of the collission hitList, but it didnt work ,

what is the best way to chive this !!! and if there is a short way it would be better !!!

thank you !!!

Short solutions? No way, man.

#// POST_OFFICE.PY ///////////////

BOXSIZE=32; READSTATE=21; READBIT=(2**READSTATE);

#-----------------------------

class MAILBOI:
    
    def __init__(self, owner):
        self.inbox=[]; self.outbox=[]; self.owner=owner;
        
    def send(self, other, subject, body=""):        
        if len(self.outbox) >= BOXSIZE: self.outbox=self.outbox[1:];
        self.outbox.append((subject, body)); other.state|=READBIT;
        other['mail'].inbox.append(self.outbox[-1]);
    
    def read(self, n):
        rt = self.inbox[-n:]; self.inbox=self.inbox[:-n]
        if not len(self.inbox): self.owner.state&=~READBIT;
        
        return rt;

So here’s a class, and what’s the deal with this?

  1. It sets a single bit of the statemask whenever you’re sent any messages.
  2. When that state is on, you process your inbox, and the state is deactivated automatically once the inbox is empty.

How do I use this?

#// INIT /////////////////////

from POST_OFFICE import MAILBOI;
from bge.logic   import getCurrentController, getCurrentScene;
scene = getCurrentScene();

ob_list = [ob for ob in scene.objects if "mail" in ob];
for ob in ob_list: ob['mail']=MAILBOI(ob);

#// SEND /////////////////////

from bge.logic   import getCurrentController, getCurrentScene;
scene = getCurrentScene();

own   = getCurrentController().owner;
other = scene.objects["Cube"];
own['mail'].send(other, "Hello", body="");

#// READ /////////////////////

from bge.logic import getCurrentController;
own=getCurrentController().owner; rt=own['mail'].read(1);
for subject, body in rt: print(f"{subject}: {body}");

And here’s what the logic looks like:

The reciever will start at state 0, run state 0 and 21 simultaneously as the messages are being read, then go back to the original state once that is over.

And before Randy even thinks of pointing out I’m using always on pulse: this runs and kills itself.

Now, onto your actual question: how do I make an ifchain out of a list? Aaah, you people always ask the darndest things. Tell you what, here’s an oversimplification:

  1. Just make both the subject and body of the message strings
  2. Use them as condition:instruction.

What is the idea here? Like say, we have

subject="own['powerlevel'] >= 9000"

and

body=f"functionName(*{args}, **{kwargs})"

Now you can just go into read all like,

for subject, body in rt:
    if eval(subject): eval(body);

But you KNOW this is terrible, right? It is, and it is python after all. But worse than python itself, this won’t exactly get cached into those pesky little bytecode dumps; so basically everytime IS the first time.

Which gets us to the next point in evolution, which would be generating python code from more abstract parameters, writting it to it’s own file and running that so a cache can be generated. It isn’t half as hard as it sounds. But all in due time.

Though if all you wanted is to check for property x and substract y from life then x is a string, that is subject, y is an int, that is body, and so it’s all like, freaking

for subject, body in rt:
    if own[subject]: own["life"] -= body;

And I just lost about an hour elaborating a response to an issue that’s likely much more simpler than I’m giving it credit for, but hey. I felt like sharing MAILBOI with the world.

1 Like

ok
first of all …
thank you so much for giving a time to understand what i want and creat this amazing thing. altho i am not sure i fully understand it all,
i am going to speend my next days dismanteling it and trying to understand it bit by bit …

so i am still new into this … i am taking things one at a time
what i am trying to find in case your not sure you understand me, is
imagin i have 3 types of monsters…
[rat] [wolf] [bear]
each one of thim sends an XP point message whene thy die.
rat sends [rat xp]
wolf sends [wolf xp]
bear sends [bear xp]
what i want is to have a message sensor that can recev thise messages, so that i can assign the messages into effecting the player.

[rat xp] will add own[“XP”]+=1
[wolf xp] will add own[“XP”]+=5
[bear xp] will add own[“XP”]+=20

and so on .
again thanks alot for replaying and creating this amazing peice of work !!!

Here, this does just that. I added a do damage function on top of the experience gain just to show how it can be expanded.

#// monster //////////////////////////////

from random    import choice; #random pick from list
from bge.logic import getCurrentController;

MESS=["rat xp",  "wolf xp",  "bear xp",
      "rat dmg", "wolf dmg", "bear dmg"];

own=getCurrentController().owner;
own.sendMessage("player", body=choice(testl))

#// player ///////////////////////////////

GAMEDICT={
    "rat" :{"xp": 1, "dmg":1},
    "wolf":{"xp": 5, "dmg":2},
    "bear":{"xp":20, "dmg":5}
    }

def addxp(own, key):
    own["XP"  ] += GAMEDICT[key]["xp" ];
    print("Gained xp!");
    
def dodmg(own, key):
    own["Life"] -= GAMEDICT[key]["dmg"];
    print("Received damage!");
    
GAMEDICT["xp"]=addxp; GAMEDICT["dmg"]=dodmg;

#-----------------------------------------

from bge.logic import getCurrentController
own=getCurrentController().owner;
sens=own.sensors["Message"];

if sens.bodies:
    for s in sens.bodies:
        monster, value = s.split(" ");       
        GAMEDICT[value](own, monster);

There are two objects, monster and player.

Monster sends a message with subject “player” and a random string from the MESS list as the message body.

Player has a single message sensor listening for the subject “player”. It checks for message bodies from the sensor. It then separates the message at whitespaces, so you have two strings (monster’s name and value-type).

We use these strings to index into a dictionary and retrieve data. I’m using the value string to retrieve a function to call, and passing that function the monster’s name so that it can retrieve the right value.

So now you’ve gone from six evaluations at best, right down to just one. This isn’t just faster, this is easier to expand. Play around with it.