Message Calls Are The Devil

Error message

Deprecated function: implode(): Passing glue string after array is deprecated. Swap the parameters in drupal_get_feeds() (line 394 of /var/www/pied-piper.ermarian.net/includes/common.inc).
AuthorTopic: Message Calls Are The Devil
Lifecrafter
Member # 6193
Profile Homepage #0
I was writing my first script involving messaging today, (I've avoided it like the plague) and have encountered some difficulties.

The idea is fairly simple. One creature(the overseer) sends out a message of 1 to all nearby characters. Another script(the slave) turns to hostile B if it doesn't receive a message for two consecutive turns. Basically its Kel's "traitor" but with messages instead of SDFs.

The problem I've encountered is that the slave creature is constantly forgetting its message. I tried saving the message as a variable, but the script runs multiple times each turn and just winds up writing over it with a -1. See for yourself, here's the relevant part of the slave script.

beginstate START_STATE;
message = my_current_message();
if(message == 1){
nomess = 0;
set_attitude(ME,10);
}
if(message == -1){
if(nomess == 1){
message_dialog("The ogre, realizing that its tormentor is dead, promptly turns on its former masters.","");
set_attitude(ME,11);
}
if(nomess == 0)
nomess = 1;
}

if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
else set_target(ME,-1);
}

// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
}

// Have I been hit? Strike back!
if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
}
break;
I can get it to work if I replace the do_attack()'s with end_combat_turn, but obviously that makes it just sit there. The most frustrating thing is that the behavior seems fairly random, one slave will revolt while others remain hostile, and then several turns later they too will revolt. Any suggestions would be appreciated.

--------------------
Guaranteed to blow your mind.

Frostbite: Get It While It's...... Hot?
Posts: 900 | Registered: Monday, August 8 2005 07:00
Agent
Member # 2820
Profile #1
I am pretty sure you are just experimenting, so this script is fine for that purpose. However, if you need this to do something important, there are simpler and more reliable ways to do this.

I haven't confirmed your statement about the reassignment of message in the same turn when START_STATE runs again, but I'll assume your take on the situation is right and I present this code which should work:

beginstate START_STATE;
message = my_current_message();
if(message == 1){
nomess = get_current_tick();
set_attitude(ME,10) // is this really necessary?
}
if(message == -1){
if(tick_difference(nomess,get_current_tick()) >= 2){
message_dialog("The ogre, realizing that its tormentor is dead, promptly turns on its former masters.","");
set_attitude(ME,11);
}

if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
else set_target(ME,-1);
}

// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
}

// Have I been hit? Strike back!
if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
}
break;


--------------------
Thuryl: I mean, most of us don't go around consuming our own bodily fluids, no matter how delicious they are.
====
Alorael: War and violence would end if we all had each other's babies!
====
Drakefyre: Those are hideous mangos.
Posts: 1415 | Registered: Thursday, March 27 2003 08:00
Lifecrafter
Member # 6193
Profile Homepage #2
Actually this was for real. I'm using it in my new scenario.

So anyway, I had to fix the code a little. Heres what the working version looked like.
message = my_current_message();
if(message == 1){
nomess = -1;
set_attitude(ME,10); // For the record, this is here in case an overseer comes back into range, so the ogre will straighten itself out.
}

if(message == -1){
if((tick_difference(nomess,get_current_tick()) >= 1) && (nomess != -1)){
message_dialog("The ogre, realizing that its tormentor is dead, promptly turns on its former masters.","");
set_attitude(ME,11);
}
nomess = get_current_tick();

}
if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
else set_target(ME,-1);
}
// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
}
// Have I been hit? Strike back!
if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
}
Your tick suggestion really put me on the right track. Thanks a bunch. By the way, what easier ways to do you mean? I'm always a fan of shortcuts, and I'd run through a lot of different ideas and couldn't come up with anything that would work for how I'm using this code.

Ok, slightly funny story, I made the changes above, and knew it should be working, but it wasn't. After slamming my head on the wall for about five minutes it hit me. Much to my chagrin, I was testing it in a town that I had frozen in time (doh).

--------------------
Guaranteed to blow your mind.

Frostbite: Get It While It's...... Hot?
Posts: 900 | Registered: Monday, August 8 2005 07:00
Infiltrator
Member # 3040
Profile #3
I think that creatures will receive a message in the same turn that it is sent iff their number is higher than that of the sender; otherwise, they'll get it the next turn.

Maybe you might look into that?

--------------------
5.0.1.0.0.0.0.1.0...
Posts: 508 | Registered: Thursday, May 29 2003 07:00
Agent
Member # 2820
Profile #4
Actually, if you have not modified the rest of the control structure of this script, there are a handful of possible problems.

As wz pointed out, the NPC must act after its overseer in order for this to work.

The message dialog seems to assume that the overseer must be dead if it has not been around for a round. However, because you said the monster script reverts it attitude when it comes back, you imply that the overseer might just be out of the area when the ogre goes rogue.

Since this code is in START_STATE, it will not have any effect while the ogre is attacking one target -- the ogre will be in state 3 for the entire duration of which. You probably do not want this because I tend to think it will be too busy attacking you to change attitudes.

Also, if you wanted to do this simply, why didn't you just use the SDF version? If you do not like SDFs for this, you could also use a set_memory_cell call on a group.

--------------------
Thuryl: I mean, most of us don't go around consuming our own bodily fluids, no matter how delicious they are.
====
Alorael: War and violence would end if we all had each other's babies!
====
Drakefyre: Those are hideous mangos.
Posts: 1415 | Registered: Thursday, March 27 2003 08:00
Lifecrafter
Member # 6193
Profile Homepage #5
The message dialog sucks because I wrote it in about 2 seconds, mostly for the purpose of alerting me when the ogre changed sides when testing the script.

As for the rest, I already had taken out state 3, but I've now added a set_target(ME,-1) to when the ogre switches sides. Also, whether the overseer acts first doesn't matter particularly much, since he has an extra turn to catch up to them. Example: Ogre doesn't get a message because it acts first, begins countdown, then next turn gets a message and doesn't revolt.

The real problem is that a slowed, forcecaged or paralyzed overseer's script doesn't get run, which means the ogres go nuts every other turn. Its not to much of a concern since I'm stripping all the default spells so this probably won't come up, but still. I'm making the overseers immune to those things just in case.

And the reason I'm not using SDF's is because I'll be using this in outdoor combats a couple of times. Since you can't set memory cells before hand in outdoor combats, or add creatures to groups, it would require making a different script for each one (Since number of overseers that have to die, etc. changes from situation to situation.) In a town I could get away with this by just using a memory cell to mark how many overseers a particular ogre should expect to have, and what flag that group would be using. In an outdoors it would take a whole new script.

--------------------
Guaranteed to blow your mind.

Frostbite: Get It While It's...... Hot?
Posts: 900 | Registered: Monday, August 8 2005 07:00
Agent
Member # 2820
Profile #6
I apologize for not noticing that you took out state 3 in your script. Could you post the whole script, by the way? I'd like to see how you set it up. I have a pretty good idea of how to improve this, but I'd have to see how you are doing it now.

--------------------
Thuryl: I mean, most of us don't go around consuming our own bodily fluids, no matter how delicious they are.
====
Alorael: War and violence would end if we all had each other's babies!
====
Drakefyre: Those are hideous mangos.
Posts: 1415 | Registered: Thursday, March 27 2003 08:00
Lifecrafter
Member # 6193
Profile Homepage #7
Nothing to apologize for. Here's the scripts for both the slave and the overseer. The slave script is pretty much what I posted last time.

Slave:
begincreaturescript;

variables;

short i,target;
short check,message,nomess,new;
short best,status,targ

body;

beginstate INIT_STATE;
set_char_script_mode(ME,2);

nomess = 0;
new = 1;
if (get_memory_cell(0) == 2)
set_mobility(ME,0);
break;

beginstate DEAD_STATE;
// Set the appropriate stuff done flag for this character being dead
if ((get_memory_cell(1) != 0) || (get_memory_cell(2) != 0))
set_flag(get_memory_cell(1),get_memory_cell(2),1);
break;

beginstate START_STATE;
message = my_current_message();
if(message == 1){
nomess = -1;
set_attitude(ME,10);
}

if(message == -1){
if((tick_difference(nomess,get_current_tick()) >= 2) && (nomess > 0)){
if(get_flag(5,0) == 0){
message_dialog("Ogres are slow and dim witted, nevertheless it only takes this
one a short amount of time to realize that there are no overseers around, and thus no threat of whips and pain. It promptly
starts attacking anything in sight.","");
set_flag(5,0,1);
}
set_attitude(ME,11);
set_target(ME,-1);
}
if(nomess == -1)
nomess = get_current_tick();

}
if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
else set_target(ME,-1);
}
// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
}
// Have I been hit? Strike back!
if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
}
break;
Overseer:
begincreaturescript;

variables;

short i,target;

body;

beginstate INIT_STATE;
set_char_script_mode(ME,2);
if (get_memory_cell(0) == 2)
set_mobility(ME,0);
break;

beginstate DEAD_STATE;
// Set the appropriate stuff done flag for this character being dead
if ((get_memory_cell(1) != 0) || (get_memory_cell(2) != 0))
set_flag(get_memory_cell(1),get_memory_cell(2),1);
break;

beginstate START_STATE;
// if I have a target for some reason, go attack it

if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
set_state(3);
else set_target(ME,-1);
}

// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
set_state(3);
}

if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
set_state(3);
}


// Otherwise, just peacefully move around. Go back to start, if I'm too far
// from where I started.
if ((my_dist_from_start() >= 6) || ((my_dist_from_start() > 0) && (get_memory_cell(0) > 0))) {
if (get_ran(1,1,100) < 40)
return_to_start(ME,1);
}
else if (get_memory_cell(0) == 0) {
fidget(ME,25);
}

// if we're in combat and the above didn't give me anything to do, just
// stop now. Otherwise, game will keep running script, and that eats up CPU time.
if (am_i_doing_action() == FALSE)
end_combat_turn();
break;

beginstate 3; // attacking
print_str("Sent");
broadcast_char_message(15,1,0);
if (target_ok() == FALSE)
set_state(START_STATE);
do_attack();
end();
break;
It seems to be working fairly well like this, although I'm still a bit distrustful of it. I've seen it act goofy too many times in the past. Oh, and I think I'm going to edit it to run a town script when the creature dies, I'll decide when I'm done with the dungeon and know whether I'll need it.
Edit: That message dialog was WAY to long, broke it up a bit.

[ Wednesday, August 30, 2006 13:26: Message edited by: Lazarus. ]

--------------------
Guaranteed to blow your mind.

Frostbite: Get It While It's...... Hot?
Posts: 900 | Registered: Monday, August 8 2005 07:00
Agent
Member # 2820
Profile #8
There are only a few changes in the following. They should account for every possibility, indoors and outdoors.

begincreaturescript;

variables;

short i,target;
short check,message,nomess = -1,new = 0; // since you can assign them values right away
short best,status,targ;

body;

beginstate INIT_STATE;
set_char_script_mode(ME,2);

if (get_memory_cell(0) == 2)
set_mobility(ME,0);
break;

beginstate DEAD_STATE;
// Set the appropriate stuff done flag for this character being dead
if ((get_memory_cell(1) != 0) || (get_memory_cell(2) != 0))
set_flag(get_memory_cell(1),get_memory_cell(2),1);
break;

beginstate START_STATE;
message = my_current_message();
if(message == 1){
nomess = -1;
set_attitude(ME,10);
}

if(message == -1){
if((tick_difference(nomess,get_current_tick()) >= 2) && (nomess > -1)){
if(get_flag(5,0) == 0){
message_dialog("Ogres are slow and dim witted, nevertheless it only takes this
one a short amount of time to realize that there are no overseers around, and thus no threat of whips and pain. It promptly
starts attacking anything in sight.","");
set_flag(5,0,1);
}
set_attitude(ME,11);
set_target(ME,-1);
}
if(nomess == -1)
nomess = get_current_tick();

}

if (target_ok()) { // the do_attack() call was missing
if (dist_to_char(get_target()) <= 16)
do_attack();
else set_target(ME,-1);
}

// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
}
// Have I been hit? Strike back!
if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
}
break;
begincreaturescript;

variables;

short i,target;

body;

beginstate INIT_STATE;
set_char_script_mode(ME,4); // setting this to run every turn period accounts for at least one special case I can think of
if (get_memory_cell(0) == 2)
set_mobility(ME,0);
break;

beginstate DEAD_STATE;
// Set the appropriate stuff done flag for this character being dead
if ((get_memory_cell(1) != 0) || (get_memory_cell(2) != 0))
set_flag(get_memory_cell(1),get_memory_cell(2),1);
break;

beginstate START_STATE;
// if I have a target for some reason, go attack it

if (target_ok()) {
if (dist_to_char(get_target()) <= 16)
set_state(3);
else set_target(ME,-1);
}

// Look for a target, attack it if visible
if (select_target(ME,8,0)) {
do_attack();
set_state(3);
}

if (who_hit_me() >= 0) {
set_target(ME,who_hit_me());
do_attack();
set_state(3);
}


// Otherwise, just peacefully move around. Go back to start, if I'm too far
// from where I started.
if ((my_dist_from_start() >= 6) || ((my_dist_from_start() > 0) && (get_memory_cell(0) > 0))) {
if (get_ran(1,1,100) < 40)
return_to_start(ME,1);
}
else if (get_memory_cell(0) == 0) {
fidget(ME,25);
}

// if we're in combat and the above didn't give me anything to do, just
// stop now. Otherwise, game will keep running script, and that eats up CPU time.
if (am_i_doing_action() == FALSE)
end_combat_turn();
break;

beginstate 3; // attacking

print_str("Sent");
broadcast_char_message(15,1,0);

if (target_ok() == FALSE)
set_state(START_STATE);
do_attack();
break;
If you want to make a nice live-action scene with an overseer beating up an ogre, I have the perfect script for that in case you'd like to see it.

[ Wednesday, August 30, 2006 21:00: Message edited by: Garrison ]

--------------------
Thuryl: I mean, most of us don't go around consuming our own bodily fluids, no matter how delicious they are.
====
Alorael: War and violence would end if we all had each other's babies!
====
Drakefyre: Those are hideous mangos.
Posts: 1415 | Registered: Thursday, March 27 2003 08:00
Lifecrafter
Member # 6193
Profile Homepage #9
Thanks for the help, I haven't tried the new version yet but I don't see why it shouldn't work.

I think I'll have to take a pass on the ogre getting whooped on. The first time the party encounters them will be outdoors, which eliminates putting the sequence there. By the time you reach the dungeon it will already have been established through message dialogs and Friendly NPC dialog that the ogres are mistreated. Throwing a sequence like that in the middle of a hack n' slash dungeon, while tempting, would probably just break up the atmosphere (plus I assume you mean the sparring script you wrote at the codex, in which case the party will just wind up killing the ogre and overseer before they realize what is going on :P )

Edit: Actually having an overseer beating up on ogres and miners alike would be kinda interesting. I'll put it in and see how it looks.

[ Thursday, August 31, 2006 16:22: Message edited by: Lazarus. ]

--------------------
Guaranteed to blow your mind.

Frostbite: Get It While It's...... Hot?
Posts: 900 | Registered: Monday, August 8 2005 07:00